基于AVR单片机--Atmega16的串口通信使用
- 格式:doc
- 大小:21.00 KB
- 文档页数:2
基于ATmega16单片机的USART串口通信测试程序/************************************************************** *************** 编译环境:ICC AVR。
文件名:基于ATmega16单片机的USART串口通信测试程序功能:利用ATmega16的USART,从TXD异步串出数据,将TXD 与RXD短接,从RXD输入,通过PC口送到一个LED数码管显示,实现了自发自收的过程?作者:赵国朋班级:鹏程001时间:2013年04月5日修改:无备住:一.硬件接口电路描述1.晶振:8MHz2.MCU的PC口与共阴极数码管相接3.TXD与RXD相接TXD --- RXD/************************************************************** ***************/ #include //包含单片机型号头文件#include //包含"位操作"头文件#define uchar unsigned char //宏定义#define uint unsigned int#define ulong unsigned long#define BAUD 9600 //波特率采用9600b/s#define CRYSTAL 8000000 //系统时钟为8MHz//计算和定义波特率设置参数#define BAUD_SETTING (uint)((ulong)CRYSTAL/(16*(ulong)BAUD)-1)#define BAUD_H (uchar)(BAUD_SETTING>>8)#define BAUD_L (uchar)(BAUD_SETTING)//USART控制和状态寄存器的标志位定义#define FRAMING_ERROR (1<<fe)< bdsfid="122" p=""></fe)<>#define PARITY_ERROR (1<<pe)< bdsfid="124" p=""></pe)<>#define DATA_OVERRUN (1<<dor)< bdsfid="126" p=""></dor)<>#define DATA_REGISTER_EMPTY (1<<udre)< bdsfid="128" p=""></udre)<>#pragma interrupt_handler USART_Rx_Isr:12 //USART接收中断服务#pragma data:dataflash Duan_table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d, 0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};// 显示段码值0~F /************ MCU初始化函数**************//************************************************************** **************** 函数名:MCU_Init()功能:MCU初始化参数:无返回值:无/************************************************************** **************** /void MCU_Init(){PORTC=0X00;DDRC=0XFF;PORTD=0X03;DDRD=0X02;}/************ USART初始化函数**************//************************************************************** **************** 函数名:USART_Init()功能:USART初始化参数:无返回值:无/************************************************************** **************** /void USART_Init(){// DDRD=0X02;//PORTD=0X03;UCSRA=0X00;UCSRB=(1<<rxcie)|(1<<rxen)|(1<<=""></rxcie)|(1<<rxen)|( 1<//UCSRB=0X98;UCSRC=(1<<ursel)|(1<<ucsz1)|(1<<="" bdsfid="161" p=""></ursel)|(1<<ucsz1)|(1<//UCSRC=0X86UBRRH=BAUD_H;UBRRL=BAUD_L;}/************ USART中断服务函数**************//************************************************************** **************** 函数名:USART_Rx_Isr()功能:USART中断服务,将欲显示的数码送到I/O寄存器参数:无返回值:无/************************************************************** **************** /void USART_Rx_Isr(){uchar status,data;//DDRC=0XFF;status=UCSRA;data=UDR;if((status&(FRAMING_ERROR|PARITY_ERROR|DATA_OVERRU N))==0)PORTC=Duan_table[data];}/************ USART发送数据函数**************//************************************************************** **************** 函数名:USART_Transmit()功能:将要发送的数据送到USART缓冲区UDR中参数:uchar data返回值:无/************************************************************** **************** /void USART_Transmit(uchar data)while(!(UCSRA&DATA_REGISTER_EMPTY));UDR=data;}/************ 延时函数**************//************************************************************** **************** 函数名:Delay_Us()、Delay_Ms()功能:微秒级、毫秒级延时参数:Us --- 欲延时的us数Ms --- 欲延时的ms数返回值:无/****************************************************************************** /void Delay_Us(uint Us){uint i;Us=Us*5/4; //5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值for( i=0;i<us;i++);< bdsfid="203" p=""></us;i++);<>}void Delay_Ms(uint Ms){uint i,j;for( i=0;i<ms;i++)< bdsfid="209" p=""></ms;i++)<>for(j=0;j<1141;j++);//1141是在8MHz晶振下,通过软件仿真反复实验得到的数值}/************ 主函数**************//************************************************************** **************** 函数名:main()功能:参数:无返回值:无/************************************************************** **************** /void main()uchar i=0;//定义变量MCU_Init();USART_Init();SREG=BIT(7);//开全局中断while(1){for(i=0;i<16;i++) {USART_Transmit(i); Delay_Ms(500);}}}。
//ATMEGA16的USART串口发送与接收数据示例程序,采取中断的方式//发送200个FF,接收数据显示在数码管上,接收数据格式如09//编译环境 ICCAVR//系统时钟7.3728MHZ,设置熔丝位为外部高频石英晶体振荡,启动时间4.1ms//作者:David//日期:2013.10.20//*********************************************************************** // 包含文件//***********************************************************************#include <iom16v.h>#include <macros.h>#include <string.h>#include <stdio.h>#include <signal.h> //中断信号头文件//*********************************************************************** // 定义变量区//*********************************************************************** #define CH451_RESET 0x0201 //复位#define CH451_LEFTMOV 0x0300 //设置移动方式-左移#define CH451_LEFTCYC 0x0301 //设置移动方式-左循#define CH451_RIGHTMOV 0x0302 //设置移动方式-右移#define CH451_RIGHTCYC 0x0303 //设置移动方式-右循#define CH451_SYSOFF 0x0400 //关显示、键盘、看门狗#define CH451_SYSON1 0x0401 //开显示#define CH451_SYSON2 0x0403 //开显示、键盘#define CH451_SYSON3 0x0407 //开显示、键盘、看门狗功能#define CH451_DSP 0x0500 //设置默认显示方式#define CH451_BCD 0x058f //设置BCD译码方式#define CH451_TWINKLE 0x0600 //设置闪烁控制#define CH451_DIG0 0x0800 //数码管位0显示#define CH451_DIG1 0x0900 //数码管位1显示#define CH451_DIG2 0x0a00 //数码管位2显示#define CH451_DIG3 0x0b00 //数码管位3显示#define CH451_DIG4 0x0c00 //数码管位4显示#define CH451_DIG5 0x0d00 //数码管位5显示#define CH451_DIG6 0x0e00 //数码管位6显示#define CH451_DIG7 0x0f00 //数码管位7显示#define l ed0 0x0000 //数码管位0显示的数据0#define l ed1 0x0001 //数码管位0显示的数据1#define l ed2 0x0002 //数码管位0显示的数据2#define l ed3 0x0003 //数码管位0显示的数据3#define l ed4 0x0004 //数码管位0显示的数据4#define l ed5 0x0005 //数码管位0显示的数据5#define l ed6 0x0006 //数码管位0显示的数据6#define l ed7 0x0007 //数码管位0显示的数据7#define l edno 0x0010 //数码管灭#define dclk0 PORTD &= ~(1 << PD6) //串行数据时钟,上升延激活#define dclk1 PORTD |= (1 << PD6)#define din0 PORTD &= ~(1 << PD5) //串行数据输出,接CH451的数据输入#define din1 PORTD |= (1 << PD5)#define load0 PORTD &= ~(1 << PD4) //串行命令加载,上升延激活#define load1 PORTD |= (1 << PD4)#define uchar unsigned char#define uint unsigned int#define ulong unsigned long#define fosc 7372800 //晶振频率#define baud 9600 //设置波特率的大小uint tx_count=200,tx_flag=0xff;uchar A1,A2,A3;uchar usart_tx_data;uchar usart_rx_data;uchar table[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06, //显示用数据0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};//*************************************************************************// 初始化子程序//*************************************************************************void system_init(){PORTD=0x7F; //PD0设置为输入,PD1输出DDRD=0x72; //上拉电阻使能有效}void ch451_init() //先低后高,选择4线输入{din0;din1;}void usart_init(){UCSRB = 0x00;UCSRA=0x00; //单倍速模式UBRRL = (fosc/16/baud-1)%256; //写波特率的值UBRRH = (fosc/16/baud-1)/256;UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //UCSRC=086;写UCSRC寄存器 //异步通信无校验,8位数据1位停止位UCSRB=0xF8; //接收中断和发送中断允许}//***********************************************************************// 延时程序////***********************************************************************void delay_1ms(void){unsigned int i;for(i = 1; i < (unsigned int)(1144 - 2); i++);}void delay_ms(unsigned int n){unsigned int i = 0;while(i < n){delay_1ms();i++;}}//*************************************************************************// 数据处理函数//*************************************************************************void data_do(uchar temp_d){uchar A2t;A1=temp_d/100; //分出百,十,和个位A2t=temp_d%100;A2=A2t/10;A3=A2t%10;}//*************************************************************************// 串口相关中断服务子程序//************************************************************************* /* //数据发送结束中断向量#pragma interrupt_handler USART_TXC:14void USART_TXC() //中断服务程序{delay_ms(10); //相关操作}*///数据接收结束中断向量#pragma interrupt_handler USART_RXC:12void USART_RXC() //中断服务程序{CLI();//关中断usart_rx_data=UDR; //将接收到的数据取出data_do(usart_rx_data); //数据处理,得到个位十位百位SEI(); //开中断}/* //数据寄存器空中断向量#pragma interrupt_handler USART_UDRE:13void USART_UDRE() //中断服务程序{UDR=usart_tx_data; //发送数据到数据寄存器tx_count--;if(tx_count==0x00){tx_flag=0x01;}}*///************************************************************************* // 串口发送相关程序//************************************************************************* //发送单个字符void PutChar(char c){//PORTC |= (1 << PC3); //改变1487控制口为输出态,PC3=1 发送允许,接收禁止while(!(UCSRA & (1 << UDRE)));UDR = c;while(!(UCSRA&(1<<TXC)));UCSRA |= (1 <<TXC);//将发送结束标志位清零//PORTC &= ~(1 << PC3); //改变1487控制口为输出态,PC3=0 接收允许,发送禁止}//发送不带换行回车的字符串void PutNStr(unsigned char *Str){while (*Str != '\0'){PutChar(*Str);Str++;}}//发送带换行回车的字符串void PutStr(unsigned char *Str){while (*Str != '\0'){PutChar(*Str);Str++;}PutChar(0x0D);PutChar(0x0A);}//*************************************************************************// 输出命令子程序// 定义一无符号整型变量存储12字节的命令字//************************************************************************void ch451_write(unsigned int command){unsigned char i;load0; //命令开始for(i=0;i<12;i++){ //送入12位数据,低位在前if(command&1){din1;}elsedin0;dclk0;dclk1; //上升沿有效command>>=1;}load1; //加载数据}//*************************************************************************// 显示函数//*************************************************************************void display(uchar b_data,uchar s_data,uchar g_data){system_init();ch451_init();ch451_write(CH451_SYSOFF); //关显示、键盘、看门狗ch451_write(CH451_SYSON1); //开显示ch451_write(CH451_BCD); //设置BCD译码方式ch451_write(CH451_TWINKLE); //设置闪烁控制ch451_write(CH451_DIG0|table[b_data]); //显示接收到的值ch451_write(CH451_DIG1|table[s_data]);ch451_write(CH451_DIG2|table[g_data]);ch451_write(CH451_DIG3|ledno);ch451_write(CH451_DIG4|ledno);ch451_write(CH451_DIG5|ledno);ch451_write(CH451_DIG6|ledno);ch451_write(CH451_DIG7|ledno);}//*************************************************************************// 主程序//*************************************************************************void main(){system_init(); //系统初始化usart_init(); //usart串口初始化配置//usart_tx_data=0xff;SREG|=0x80; //开启全局中断while(1){/*while(tx_flag!=0x01) //数据发送是否完成,也可用发送完成中断 {//usart_tx_data=0xff;PutChar(0xFF);tx_count--;if(tx_count==0x00){tx_flag=0x01;}//delay_ms(10);}*///UCSRB=0xF0;display(A1,A2,A3); //显示接收到的数据 }}。
ALU- 算术逻辑单元AVR ALU 与32 个通用工作寄存器(R0-R31)直接相连。
寄存器与寄存器之间、寄存器与立即数之间的ALU 运算只需要一个时钟周期。
ALU 操作分为3 类:算术、逻辑和位操作。
此外还提供了支持无/ 有符号数和分数乘法的乘法器。
具体请参见指令集。
状态寄存器状态寄存器包含了最近执行的算术指令的结果信息。
这些信息可以用来改变程序流程以实现条件操作。
如指令集所述,所有ALU 运算都将影响状态寄存器的内容。
这样,在许多情况下就不需要专门的比较指令了,从而使系统运行更快速,代码效率更高。
在进入中断服务程序时状态寄存器不会自动保存,中断返回时也不会自动恢复。
这些工作需要软件来处理。
AVR 中断寄存器SREG 定义如下:•Bit 7 –I: 全局中断使能I 置位时使能全局中断。
单独的中断使能由其他独立的控制寄存器控制。
如果I 清零,则不论单独中断标志置位与否,都不会产生中断。
任意一个中断发生后I 清零,而执行RETI指令后I 恢复置位以使能中断。
I 也可以通过SEI 和CLI 指令来置位和清零。
•Bit 6 –T: 位拷贝存储位拷贝指令BLD 和BST 利用T 作为目的或源地址。
BST 把寄存器的某一位拷贝到T,而BLD 把T 拷贝到寄存器的某一位。
•Bit 5 –H: 半进位标志半进位标志H 表示算术操作发生了半进位。
此标志对于BCD 运算非常有用。
详见指令集的说明。
•Bit 4 –S: 符号位, S = N ⊕VS 为负数标志N 与2 的补码溢出标志V 的异或。
详见指令集的说明。
•Bit 3 –V: 2 的补码溢出标志支持2 的补码运算。
详见指令集的说明。
•Bit 2 –N: 负数标志表明算术或逻辑操作结果为负。
详见指令集的说明。
• Bit 1 – Z: 零标志表明算术或逻辑操作结果为零。
详见指令集的说明。
• Bit 0 – C: 进位标志表明算术或逻辑操作发生了进位。
详见指令集的说明使用CLI 指令来禁止中断时,中断禁止立即生效。
AVR通过串口给芯片烧录程序(ATMega16)AVR通过串口给芯片烧录程序(ATMega16)相信大家都用过STC系列的51单片机,STC系列的单片机烧录程序都很简单,只需要通过串口就可以实现程序的烧录。
于是就想让avr 的芯片也能实现通过串口就能下载的功能,这样就可以省去购买usbasp下载线或者高压编程器的费用了。
仔细研究avr的芯片手册,发现都是带有bootloader功能,同时这个bootloader功能可以读写芯片的整个flash存储区,并且包括bootloader区,而且还有另外一个特点:如果bootloader功能开启以后,每次复位都会从bootloader启动。
接下来再来研究一下STC芯片的烧录功能:当在烧录软件中按下“下载”按钮以后,烧录软件会通过传给给STC芯片不停的发送一串数据,此时给STC芯片下电,然后上电,芯片上电以后,首先检测是否有烧录的请求,如果有就开始烧录程序,如果没有就开始执行芯片flash中的程序。
于是就有一个大概的思路了,可以给avr的芯片写一个bootloader的串口通信的程序,首先检测是否有烧录请求,如果有就更新flash中的程序,如果没有烧录请求,则执行flash中原有的程序。
经过几天的努力这个通过串口给atmega16烧录程序的固件和上位机终于完成了,为了方便大家这里共享处原理图和固件程序。
其实这种功能应该有人已经实现了,至少国外的开源硬件arduino就是通过这种方式给atmega8烧录程序的,但是atmega16我没有找到现成的,于是就自己实现了一个。
烧录软件使用winavr中的avrdude程序。
这也是一个开源项目,avrdude是一个控制台程序,操作不是很方便,于是写了一个应用程序封装了一下。
原理图:原理图实际上就是一个带有串口的avr最小系统。
烧录bootloader程序:下载ATMega16串口下载.rar 安装包,解压到本地目录,使用usbasp把“bootloader" 文件夹下的固件烧录到atmega16里,然后修改熔丝位:验证烧录程序:把自制的板子通过串口和电脑相连,运行“AvrSelfProgram.exe” 程序:在软件中选择正确的串口,并浏览打开要烧录的hex固件,此时按下板子上的复位按钮,然后点击“写FLASH”按钮。
1、编译环境:CodeVisionAVR2、功能:实现以5AH开头的6个字节数据帧的接收及发送3、接收及发送方式:中断接收,查询发送4、校验方式:所有字节相加模除256等于0则接收正确,否则不予接收程序如下所示:#include "mega16.h"#define uchar unsigned char #define uint unsigned int #define BAUD 9600 #define F_CLK 400000 0#define MATCH_OK 1; #define MATCH_ERROR 0; #define UDRE 5volatile uchar i=0;volatile uchar recc_flag=0; //命令字节接收标志(recieve command 简写成 recc) volatile uchar comm_flag=0; //命令帧接收完毕标志(command 简写成 comm) volatile uchar comm; //定义变量,用于传递UDR0中接收到的命令字volatile uchar command[6]={0x00,0x00,0x00,0x00,0x00,0x00}; //定义长度为6的数组用于接收长度为6字节的命令帧,并将所有元素初始化为0x00/*延时*/void delay(uint t) {while(t--); }/*****//*******帧头校验******/ uchar check_comm(void) {uchar i;uint result=0;for(i=0;i<6;i++) {result+=command[i]; }if((result%256)==0) {return MATCH_OK; } else {return MATCH_ERROR; } }/*********************/void uart_init(void) {UCSRA=0x00;UCSRB=0x98; //接收结束中断使能;数据接收使能;数据发送使能UCSRC=0x06; //工作在异步模式;无校验;1位停止位;字符长度为8位 UBRRH=(F_CLK/BAUD/16-1)/256;UBRRL=(F_CLK/BAUD/16-1)%256; //系统时钟为4MHz,波特率为9600bps }void init_device(void) {#asm("cli") //关中断PORTA=0x04; DDRA=0x04; PORTB=0xFE; DDRB=0xFF; PORTD=0xFF; DDRD=0x02; MCUCR=0x00; TIMSK=0x00;uart_init(); //串口初始化#asm("sei") //重开中断 }interrupt[USART_RXC] void usart_rec(void) {comm=UDR; recc_flag=1; }/*****USART0口发送命令字节程序*****/ void usart0_transcomm(uchar x) {while(!(UCSRA&(1<<UDRE))); //数据寄存器空时才能发送数据 UDR=command[x]; }/**********************************//*****命令帧的单个字节存储程序******/ void save_single_byte(uchar y) {if(y<6){command[y]=comm;} recc_flag=0; }/***********************************//********命令帧保存程序********/ void save_comm(void) {uchar mount=5;if(recc_flag==1) //接收标志置位,说明接收到命令字,则存储 {save_single_byte(i);i++; //指向下一个数组元素 if(command[0]!=0x5A) {i=0;#asm("cli")delay(1000000); #asm("sei") }if(i==6) //若数组存满6个字节{comm_flag=1; //命令帧接收完毕,将接收完毕标志置位 } } }/*****************************//******USART0发送命令帧程序******/ void send_comm(void) {uchar j;if(comm_flag==1) //命令帧接收完毕后才允许发送,////应在发送前进行校验,在此不予考虑//// {#asm("cli")if(check_comm()) {for(j=0;j<6;j++) {usart0_transcomm(j); //调用单字节发送程序 } }#asm("sei") i=0; }comm_flag=0; //命令帧发送完毕后,接收完毕标志清零 }/*******************************//****主程序****/ void main(void) {init_device();while(1) {save_comm(); send_comm(); }}。
基于AVR单片机--Atmega16的串口通信使用
//以下程序经验正可以用,MCU:M16,晶振:8M,直接用USB转串口线上的公头(针头),
//第2针(RXD)接M16上的PD1口(15脚TXD),第3针(TXD)接M16上的PD0口(14脚RXD),
//第5针接地,此时若板上有MAX232,则需把MAX232芯片去掉,这样才能正常工作
#include<avr/io.h>
#include<avr/interrupt.h>
#define uchar unsigned char
#define uint unsigned int
#define fosc 8000000//晶振频率
#define BAUD 9600 //波特率
void USART_send(uchar date)//发送一个字节
{
while(!(UCSRA&(1<<UDRE)));//等待USART数据寄存器为空,UDRE为1说明缓冲器为空,已准备好进行数据接收或发送
UDR=date;//发送数据
}
void init()
{
DDRB=0xff;//设置PB口为输出
PORTB&=~(_BV(PB4)|_BV(PB5)|_BV(PB6)|_BV(PB7));//让高4位的LED灭
//波特率寄存器设置
UBRRH=(fosc/BAUD/16-1)/256;
UBRRL=(fosc/BAUD/16-1)%256;
//UCSRB|=_BV(RXEN)|_BV(TXEN)|_BV(RXCIE);
UCSRB|=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);//使能发送,接收,接收完成中断
sei();//开全局中断
}
int main()
{
init();
USART_send('d');//发送数据'd'
while(1);
}
volatile char date1;
SIGNAL(SIG_UART_RECV)
{
date1=UDR;//接收数据
PORTB=date1;
}。