hrefspace

 找回密码
 立即注册
搜索
热搜: PHP PS 程序设计
查看: 421|回复: 0

串口实验

[复制链接]

604

主题

616

帖子

1951

积分

版主

Rank: 7Rank: 7Rank: 7

积分
1951
发表于 2024-3-15 09:07:42 | 显示全部楼层 |阅读模式
本程序简单的示范了如何使用ATMEGA16的USART
USART的设置
波特率的计算
发送采用查询方式
接收采用中断方式
除非有特殊格式要求,否则不建议使用 printf函数库,该函数会耗用3~6KB程序空间
这里的应用比较简单,所以自己编写了put_c/put_s函数。
出于简化程序考虑,各种数据没有对外输出,学习时建议使用JTAG ICE硬件仿真器
  1. #include <[url=http://www.mcuzx.net]AVR[/url]/io.h>#include <avr/delay.h>#include <avr/signal.h>#include <avr/interrupt.h>/*注: 内部函数_delay_ms() 最高延时  262.144mS@1MHz    为了使 _delay_ms()函数的延时正确,须在makefile中设定F_CPU为实际的系统时钟频    本范例为7.3728MHz外部石英晶体振荡器 即 F_CPU=7372800    因为7.3728MHz能生成多种标准的通讯波特率。        如果使用其他系统时钟频率,注意 波特率误差不要超过 +/-1%.    做USART通讯时,除非你掌握了校准技术,否则请不要使用内部/外部RC振荡器*///管脚定义#define PIN_RXD   0  //PD0   RXD#define PIN_TXD   1  //PD1   TXD#define LED0   0  //PB0#define LED1   1  //PB1#define LED2   3  //PB3//常量定义#define BAUDRATE        9600 //波特率//#define F_CPU   7372800  //这个已经在makefile里面定义了//宏定义#define LED0_ON()  PORTB|= (1<<LED0)   //输出高电平,灯亮#define LED0_OFF()  PORTB&=~(1<<LED0) //输出低电平,灯灭#define LED1_ON()  PORTB|= (1<<LED1)#define LED1_OFF()  PORTB&=~(1<<LED1)#define LED2_ON()  PORTB|= (1<<LED2)#define LED2_OFF()  PORTB&=~(1<<LED2)//51系列的高电平输出能力很弱,低电平也仅能点亮LED.所以常见输出低电平才灯亮的接法。//AVR芯片的高低驱动能力都很强,甚至能推动8字数码管的公共极,怎么接都没问题。 //全局变量//如果变量会在中断服务程序中被修改,须加volatile限定volatile unsigned char FLAG;    //按键标志volatile unsigned char PC_COMMAND;  //PC发出的当前命令volatile unsigned char RX_BUFFER[16]; //存放接收数据的数组volatile unsigned char RX_index;   //存放接收数据的个数//仿真时在watch窗口,监控这些变量。void put_c(unsigned char c) //发送采用查询方式{ while( !(UCSRA & (1<<UDRE)) ); UDR=c;}void put_s(unsigned char *ptr){ while (*ptr) {  put_c(*ptr++); } put_c(0x0D); put_c(0x0A);  //结尾发送回车换行}SIGNAL(SIG_USART_RECV) //串口接收中断服务程序{ PC_COMMAND=UDR; switch(PC_COMMAND) {  case '0': //0x30 ASCII '0'   LED0_ON();   put_s("用户输入0#指令");   break;  case '1':   LED1_ON();   put_s("用户输入1#指令");   break;  case '2':   LED0_OFF();   LED1_OFF();   FLAG=!FLAG;   put_s("用户输入2#指令");   break;  default:   put_s("用户输入的指令无效!");   break; } /*   注意,使用put_s函数发送数据需要一定的时间,如果输入数据的速度过高将会导致数据丢失   所以,一般建议中断服务程序的处理时间尽量的短,只做采集数据和设标志位,命令的处理交由主程序来完成   这里只是示范简单的命令处理 */  RX_BUFFER[RX_index]=PC_COMMAND;  //保存数据到数组里面 RX_index++; if (RX_index>=16) RX_index=0;  //防止数组溢出  }void init_USART(void)//USART 初始化{    //USART 9600 8, n,1  PC上位机软件(超级终端等)也要设成同样的设置才能通讯    UCSRC = (1<<URSEL) | 0x06;    //异步,8位数据,无奇偶校验,一个停止位,无倍速    /*    UBRRH与UCSRC共用I/O 地址。因此访问该地址时需注意以下问题。    写访问    当在该地址执行写访问时, USART 寄存器选择位(URSEL)控制被写入的寄存器。    若URSEL为0,对UBRRH值更新;若URSEL为1,对UCSRC设置更新        读访问    对UBRRH 或UCSRC 寄存器的读访问则较为复杂。但在大多数应用中,基本不需要读这些寄存器            没有UBRR这个16位寄存器,因为UBRRL(0x09)/UBRRH(0x20)的地址不连续,而且UBRRH跟UCSRC共用地址    */        //U2X=0时的公式计算    UBRRL= (F_CPU/BAUDRATE/16-1)%256;    UBRRH= (F_CPU/BAUDRATE/16-1)/256;    //U2X=1时的公式计算    //UBRRL= (F_CPU/BAUDRATE/8-1)%256;    //UBRRH= (F_CPU/BAUDRATE/8-1)/256;    //也可根据数据手册的[波特率设置的例子]查得    //UBRRL = 0x2F; //set baud rate lo    //UBRRH = 0x00; //set baud rate hi    UCSRA = 0x00;    UCSRB = (1<<RXCIE)|(1<<RXEN)|(1<<TXEN);    //使能接收中断,使能接收,使能发送}void pro_coammand(void) //多字节命令的处理程序{ unsigned char i; if (RX_index>=10)  {     UCSRB&= ~(1<<RXCIE); //关断USART接收中断  put_c(0x0D);  put_c(0x0A);  //发送回车换行  put_s("Hello! 你之前输入的命令列表是:");  for (i=0;i<RX_index;i++) put_c(RX_BUFFER[i]);  put_c(0x0D);  put_c(0x0A);  put_c(0x0D);  put_c(0x0A);  //发送回车换行  RX_index=0;    //清零     UCSRB|= (1<<RXCIE); //打开USART接收中断 }}int main(void){    //上电默认DDRx=0x00,PORTx=0x00 输入,无上拉电阻    PORTA =0xFF;           //不用的管脚使能内部上拉电阻。    PORTC =0xFF;    DDRB  =  (1<<LED2)|(1<<LED1)|(1<<LED0);    //输出    PORTB =~((1<<LED2)|(1<<LED1)|(1<<LED0));    //低电平,灯灭    DDRD  =(1<<PIN_TXD);        //TXD为输出    PORTD =0xFF;    FLAG=0; init_USART(); put_s("你好!"); put_s("这是一个简单的串口实验程序"); put_s("你可以在电脑上的超级终端程按下[0][1][2]按键,模拟用户板上的按键操作");    sei();         //使能全局中断    while (1)    {        while (FLAG==0) pro_coammand();        LED2_ON();       //如果FLAG不加volatile限定(即has_volatile=0),程序将永远都运行不到这里。        while (FLAG!=0) pro_coammand();        LED2_OFF();    }}
复制代码

程序运行效果
     PC使用超级终端或SSCOM32串口调试程序,发送ASCII码的简单方法就是直接按下对应的按键
     
     例如  字符'0',即0x30 ,按下键盘上的[0]即可
     按下按键[0],LED0亮。
     按下按键[1],LED1亮。
     按下按键[2],LED0/1都熄灭, LED2是根据按键[2]的顺序来亮灭,是个乒乓键

串口实验范例.rar(32.05 KB, 下载次数: 0)2010-5-9 21:36 上传
点击文件名下载附件

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|hrefspace

GMT+8, 2024-11-1 07:58 , Processed in 0.065624 second(s), 22 queries .

Powered by hrefspace X3.4 Licensed

Copyright © 2022, hrefspace.

快速回复 返回顶部 返回列表