原创 【ATMEGA16L】实验二八:USART串口综合实验(升级版)

2009-8-14 09:14 4027 13 13 分类: MCU/ 嵌入式

》》点此进入      http://bbs.armavr.com/   ARM-AVR嵌入式开发论坛


【相关实验】


实验一:流水灯实验(八种LED点亮模式)


实验二:有源蜂鸣器驱动实验


实验三:按键扫描(用KEY选择对应LED点亮)


实验四:键盘扫描+8种LED亮灭模式控制


【ATMEGA16L】实验二四:四线制LCD1602B驱动实验        


【ATMEGA16L】实验二五:八线制LCD1602B驱动实验


【ATMEGA16L】实验二八:USART综合实验


【ATMEGA16L】实验二九:模拟比较器实验


【ATMEGA16L】实验三十:ADC实验


***********************************************************************


        昨天晚上直到深夜,依然未能使USART串口的字符串发送函数调试成功,害得一晚上没睡好。今天一大早就赶紧去各大BBS求救,一日未果。待到晚上,打开AVRVI的BBS,终于看到了希望,知名人士sunke大哥,真是一语惊醒梦中人。原来是变量定义和函数的入口参数不一致造成的。修改后,果然如此,在此感谢sunke大哥的指点。


为了更好的同大家分享经验和教训,下面贴出在论坛求教问题的内容:(请耐心读下去,教训不容错过!)


*********************************************************************************


        最近学习ATMEGA16L的串口模块,实验的过程中出现如下问题:理论上两种相同的连续字符发送方法,却有一种不正确,串口助手接收乱码,请朋友分析下,谢谢!

一、字符串定义:
const unsigned char buffer0[]="2009年03月19日23:55";
const unsigned char buffer1[]="0123456789";
const unsigned char buffer2[]="打倒日本帝国主义";
const unsigned char buffer3[]="欢迎访问http://blog.ednchina.com/xiantaozeng/";
const unsigned char buffer4[]="QQ:605987969";

二、连续发送len个字符:
/*-----------------------------------------------------------------
函数名称: void USART_Transmits03(unsigned char *SendData, unsigned int len)
函数功能: 发送字符串
参   数: SendData 发送字符串的首地址
    len   发送字符串的长度
返 回 值: 无(测试未通过)09.03.25
-----------------------------------------------------------------*/
void USART_Transmits03(unsigned char *SendData,unsigned int len)
{
unsigned int i;
for( i = 0; i < len; i++)
{
    while ( !( UCSRA & (1<<UDRE)) ); //等待发送缓冲器为空    
  UDR = SendData;
}
}

三、向串口助手发送数据
for(i=0;i<20;i++)   //发送数组buffer0里面的字符串:实验日期和时间
{
USART_Transmit(buffer0);
}
newline();//换行

USART_Transmits03(buffer1,10);//将"0123456789"发给串口助手,使用此程序串口助手接收数据错误
newline();//换行

for(i=0;i<16;i++)   //发送数组buffer2里面的字符串:打倒日本帝国主义
{
USART_Transmit(buffer2);
}
newline();//换行

四、问题:
1、使用下面程序向串口助手连续发数据,接收成功
for(i=0;i<20;i++)   //发送数组buffer0里面的字符串:实验日期和时间
{
USART_Transmit(buffer0);
}
newline();//换行

for(i=0;i<16;i++)   //发送数组buffer2里面的字符串:打倒日本帝国主义
{
USART_Transmit(buffer2);
}
newline();//换行
2、但使用下面这段程序,则串口助手接收乱码
USART_Transmits03(buffer1,10);//将"0123456789"发给串口助手,使用此程序串口助手接收数据错误
newline();//换行

3、串口助手接收数据如下图:
串口助手接收窗口
30_42638_e1e281c01d3e7dc.jpg
4、USART_Transmits03(buffer1,10);只不过是“for(i=0;i<20;i++)”程序的另一种写法,也应该是正确的操作,但为什么接收错误呢?请朋友们指点,谢谢。

五、备注:
1、笔记本没有串口,使用了串口转换器,应该不会是串口转换器的缘故吧?
2、波特率,停止位等设置均没问题。
3、单片机采用ATMEGA16L,外部3.6864MHz晶振


*********************************************************************************
回顾了问题之后,接下来就同大家分享:【ATMEGA16L】实验二八:USART串口综合实验(升级版)


一、硬件结构:


6816544e-7280-4c31-a486-24def4f10ec9.jpg 点击看大图


二、程序结构:


336b38d2-f404-481f-b5e7-9ff5dd222239.jpg


三、串口助手接收窗口


07d813c9-445c-448d-9c87-5f5fc37db651.jpg


四、程序代码:


1、main.c


/******************************************************************************
Platform: AVR mega16学习板(www.iccavr.com
Project : 实验二八:USART综合实验
Clock F : 3.6864MHz
Software: ICCAVR7.14C
Author  : 林夕依然
Version : 09.03.19
Updata  : 09.03.26  验证通过了两种不同方法的字符串发送函数是可用的
comments:
1、以学习板LED,MAX232为硬件电路。
2、接收发自电脑的数据,根据收到的对应数据,先将收到的数据原样返回电脑,并执行
   收到的数据所对应的操作:向电脑发送字符或选择LED流水模式。
3、用串口助手工具调试,理解串口通讯协议。
4、两种串口初始化方法均可使用。
5、了解学习ASCII码。
6、两种方法的字符串发送函数均可使用:
   USART_Transmits02(uchar *str)优于USART_Transmits03(uchar *str,uint len)
   因为它省去了字符个数的计算。
7、参考:AVR与虚拟仪器 http://www.avrvi.com 古欣AVR mega16 串口测试。
8、两种不同方法的字符串发送函数的验证得到了sunke9的指点,在此表示感谢。
problem :
1、一个汉字有两个字节组成
2、使用USART_Transmits02(uchar *str) 函数时,电脑接收乱码
   原因是入口参数未定义为指针,而是定义为数组,更改后接收正确
3、使用USART_Transmits03(uchar *str,uint len) 函数时,电脑接收乱码
   原因是入口参数未定义为指针,而是定义为数组,更改后接收正确
*******************************************************************************/
#include <iom16v.h>
#include <macros.h>


const unsigned char *temp1="2009年03月19日学习验证USART模块!";//31
const unsigned char *temp2="2009年3月26日两个发送字符串函数通过验证!";//40
const unsigned char *temp3="打倒日本帝国主义,打倒法西斯!";//28
const unsigned char *temp4="欢迎访问AVR单片机小组http://group.ednchina.com/65/";//50
const unsigned char buffer1[]="欢迎访问http://blog.ednchina.com/xiantaozeng/";//45
const unsigned char buffer2[]="QQ:605987969";//12
const unsigned char buffer3[]="AVR单片机技术交流群:76083971";//28


void main(void)
{
 unsigned char i="0",tmp=0;


 port_init();           //端口初始化,关闭LED
 Usart_init01();        //初始化串口方式1,波特率9600 (测试可用)
 //Usart_init02(9600);  //初始化串口方式2,波特率9600  (测试可用)
 DelayMs(5000);         //上电延时5s
 
 USART_Transmits02(temp1);//将"2009年03月19日学习验证USART模块!"发给串口助手
 newline();//换行
 
 for(i=0;i<45;i++)      //发送数组buffer1里面的字符串:EDN博客地址
 {
   USART_Transmit(buffer1);
 }
  newline();//换行
 
 USART_Transmits03(temp2,40);//将"2009年3月26日两个发送字符串函数通过验证!"发给串口助手
 newline();//换行
 
 for(i=0;i<12;i++)      //发送数组buffer2里面的字符串:QQ:605987969
 {
   USART_Transmit(buffer2);
 }
  newline();//换行
 
 USART_Transmits03(temp3,28);//将"打倒日本帝国主义,打倒法西斯!"发给串口助手
 newline();//换行
 
 while(1)
 {
  if(UCSRA&(1<<RXC))    //如果接收缓存区有数据
  {
   tmp="USART"_Receive(); //接收数据
   USART_Transmit(tmp); //发送数据
  
   if(tmp=='a')         //对接收到的数据进行,如果是a,再发一个OK回来
   {
    blank();//空格
    USART_Transmit('O');
 USART_Transmit('K');
 newline();//换行
   }
   if(tmp=='A')          //对接收到的数据进行,如果是A,再发一个Hello回来
   {
    blank();//空格
    USART_Transmits01();
 newline();//换行
   }
   if(tmp=='w'|tmp=='W') //检测接收到的数据,如果是w或W,则将AVR单片机小组网址发给电脑
   {
     blank();//空格
     USART_Transmits02(temp4);//将AVR单片机小组网址发给电脑
  newline();//换行
   }  
   if(tmp=='q'|tmp=='Q') //检测接收到的数据,如果是q或Q,则将AVR单片机技术交流群:76083971返回给电脑
   {
     blank();//空格
     for(i=0;i<28;i++)   //将"AVR单片机技术交流群:76083971"发送给电脑
     {
     USART_Transmit(buffer3);
     }
  newline();//换行
   }
   if(tmp=='1')         //如果接收到的数据是1,第1种LED模式运行
   {
    blank();//空格
    led01();
   }
   if(tmp=='2')         //如果接收到的数据是2,第2种LED模式运行
   {
    blank();//空格
    led02();
   }
   if(tmp=='3')         //如果接收到的数据是3,第3种LED模式运行
   {
    blank();//空格
    led03();
   }
   if(tmp=='4')         //如果接收到的数据是4,第4种LED模式运行
   {
    blank();//空格
    led04();
   }
   if(tmp=='5')         //如果接收到的数据是5,第5种LED模式运行
   {
    blank();//空格
    led05();
   }
   if(tmp=='6')         //如果接收到的数据是6,第6种LED模式运行
   {
    blank();//空格
    led06();
   }
   if(tmp=='7')         //如果接收到的数据是7,第7种LED模式运行
   {
    blank();//空格
    led07();
   }
  }
 }
}


2、function.c


#include <iom16v.h>
#include <macros.h>


#define uchar unsigned char
#define uint unsigned int


#define F_CPU 3686400
/************************************************
  UMSEL  模式选择
    0    异步操作
    1    同步操作


  USBS 停止位位数
    0     1
    1     2


  UCSZ2 UCSZ1 UCSZ0 字符长度
    0     0     0     5 位
    0     0     1     6 位
    0     1     0     7 位
    0     1     1     8 位
    1     0     0     保留
    1     0     1     保留
    1     1     0     保留
    1     1     1     9 位
*************************************************/
/*-----------------------------------------------------------------
函数名称: void Usart_init01(void)
函数功能: 串口初始化方式01(波特率设置用查表)
    波特率 9600 0.2% ,8bit,异步,倍速,无奇偶校验,1个停止位
参    数:
返 回 值: 无
-----------------------------------------------------------------*/
void Usart_init01(void)       //初始化串口方式1
{
  UCSRA="0X02";                 //倍速选择
  UCSRB=(1<<RXEN)|(1<<TXEN);  //使能接收,发送
  UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//8bit,异步,无奇偶校验,1个停止位
  UBRR="47"; //9600波特率,见M16_cn中文P155:Table68-72通用振荡器频率下设置 UBRR                    
}
/*-----------------------------------------------------------------
函数名称: void Usart_init02(void)
函数功能: 串口初始化方式02(波特率设置用公式)
    波特率 9600 0.2% 8bit,异步,常速,无奇偶校验,2个停止位
参    数:
返 回 值: 无
-----------------------------------------------------------------*/
void Usart_init02( uint baud )//初始化串口方式2,并设置波特率
{
uint tmp;
tmp= F_CPU/baud/16-1;        //设置波特率,见M16_cn中文P135:Table60波特率计算公式
UBRRH = (uchar)(tmp>>8);
UBRRL = (uchar)tmp;
UCSRB = (1<<RXEN)|(1<<TXEN); //接收器与发送器使能
UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ0)|(1<<UCSZ1);//异步,8bit,2停止位,无奇偶校验
}


/*-----------------------------------------------------------------
函数名称: void USART_Transmit( unsigned char data )
函数功能: 数据发送【发送5 到8 位数据位的帧】
参    数:
返 回 值: 无
说    明:直接从数据手册上拷贝过来的
-----------------------------------------------------------------*/
void USART_Transmit( uchar data )
{
while ( !( UCSRA & (1<<UDRE)) ) ;  //等待发送缓冲器为空
UDR = data;                        // 将数据放入缓冲器,发送数据
}
/*-----------------------------------------------------------------
函数名称: unsigned char USART_Receive( void )
函数功能: 数据接收【以5 到8 个数据位的方式接收数 据帧】
参    数:
返 回 值: UDR
说    明:直接从数据手册上拷贝过来的
-----------------------------------------------------------------*/
uchar USART_Receive( void )
{
while ( !(UCSRA & (1<<RXC)) );  // 等待接收数据
return UDR;                     // 从缓冲器中获取并返回数据
}
/*-----------------------------------------------------------------
函数名称: void USART_Transmits01( void )
函数功能: 连续发送字符"Hello"
参    数:
返 回 值:
-----------------------------------------------------------------*/
void USART_Transmits01( void )
{
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'H';
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'e';
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'l';
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'l';
while ( !( UCSRA & (1<<UDRE)) );
UDR = 'o';
}


/*-----------------------------------------------------------------
函数名称: void USART_Transmits02(uchar *str)
函数功能: 发送字符串(方法一)
参    数: str  发送字符串的首地址
返 回 值:
说    明:已通过验证,str必须定义为指针,调用时只需指针名即可
例    如:定义指针    uchar *buffer0="2009年03月26日23:40";
          调用函数    USART_Transmits02(buffer0);  即可
-----------------------------------------------------------------*/
void USART_Transmits02(uchar *str) //字符串
{
   while (*str)
   {
       USART_Transmit(*str);
       str++;
   }
}
/*-----------------------------------------------------------------
函数名称: void USART_Transmits03(uchar *str, uint len)
函数功能: 发送字符串(方法二)
参    数: str   发送字符串的首地址
      len   发送字符串的长度
返 回 值:
说    明:已通过验证,str必须定义为指针,调用时只需指针名即可
例    如:定义指针    uchar *buffer0="2009年03月26日23:40";
          调用函数    USART_Transmits03(buffer0,19);  即可
-----------------------------------------------------------------*/
void USART_Transmits03(uchar *str,uint len)
{
  uint i;
 for( i = 0; i < len; i++)
 {
    while ( !( UCSRA & (1<<UDRE)) );  //等待发送缓冲器为空   
  UDR = str;
 }
}


void newline()   //换行
{
   USART_Transmit(0x0d);  //发送一个回车
   USART_Transmit(0x0a);  //发送一个换行
}


void blank()    //空格
{
   USART_Transmit(0x20); 
}


3、led.c


/*******************************
Platform : AVR mega16学习板(www.iccavr.com
function :功能函数集
Clock F  : 3.6864M
Software : ICCAVR7.14C
Author   : 林夕依然
Version  : 09.02.25
comments :
********************************/
#include <iom16v.h>
#include <macros.h>


void port_init()
{
  DDRB =0XFF;
  PORTB="0XFF";
}


void LED_on()                            //打开所有LED
    {
 PORTB =0X00;
 DelayMs(100);
 } 
 
void LED_off()                           //关闭所有LED
    {
 PORTB = 0xFF;
 DelayMs(100); 
 }


void LED_01(int i)                  //LED亮灭控制
    {
    PORTB = ~BIT(i);                //输出低电平
    DelayMs(100);                   //调用延时程序
    }
 
void LED_02(int i)                  //间隔点亮
    {
 PORTB=~(BIT(i)|BIT(i-2));
 DelayMs(100);
 }
 
void LED_03(int i)                 //相临点亮
    {
 PORTB=~(BIT(i)|BIT(i-1));      //~后内容需用括号括起来
 DelayMs(100);
 }
 
void LED_04(int i)                 //发散聚集点亮
    {
 switch(i)
  {
  case 0:PORTB=0xE7;DelayMs(100);break;    //延时100ms
  case 1:PORTB=0xDB;DelayMs(100);break;
  case 2:PORTB=0xBD;DelayMs(100);break;
  case 3:PORTB=0x7E;DelayMs(100);break;
  default:break;
  }
 }
 
void LED_05(int i)                 //00,0F,F0,FF方式显示
    {
 switch(i)
  {
  case 0:PORTB=0x00;DelayMs(100);break;    //延时100ms
  case 1:PORTB=0x0F;DelayMs(100);break;
  case 2:PORTB=0xF0;DelayMs(100);break;
  case 3:PORTB=0xFF;DelayMs(100);break;
  default:break;
  }
 }
 
void LED_06(int i)
   {
   switch(i)
    {
 case 0:PORTB=0XAA;DelayMs(100);break;
 case 1:PORTB=0X55;DelayMs(100);break;
 }
   }


//8种不同的点亮模式
void led01()          //模式1:顺序点亮
    {
      unsigned char h="5",i;
  
      while(h--)
     {
        for (i = 0; i < 8; i++)     //顺序单个点亮LED
        LED_01(i);
        for (i = 6; i > 0; i--)     //逆序单个点亮LED
        LED_01(i);
  PORTB=0XFF;
     }
    }
   
void led02()         //模式2:间隔点亮
    {
      unsigned char h="5",i;
      while(h--)
      {
        for (i = 2; i < 8; i++)     //间隔顺序同时点亮
        LED_02(i);
        for (i = 6; i > 2; i--)  //间隔逆序同时点亮
        LED_02(i);
  PORTB=0XFF;
      }
    }
   
void led03()         //模式3:相临点亮
    {
      unsigned char h="5",i;


      while(h--)
      {
        for (i = 1; i < 8; i++)     //相临顺序同时点亮
        LED_03(i);
        for (i = 6; i > 1; i--)  //相临逆序同时点亮
        LED_03(i);
  PORTB=0XFF;
      }
    }  
   
void led04()       //模式4:发散聚集点亮
    {
      unsigned char h="5",i;


      while(h--)
      {
        for(i=0;i<4;i++)            //发散点亮
        LED_04(i);
        for(i=2;i>0;i--)            //聚集点亮
        LED_04(i);  
  PORTB=0XFF;  
      }
    }
   
void led05()         //模式5:四四点亮
    {
      unsigned char h="5",i;


      while(h--)
      {
        for(i=0;i<4;i++)            //四四顺序点亮
        LED_05(i);
        for(i=2;i>0;i--)            //四四逆序点亮
        LED_05(i); 
  PORTB=0XFF;   
      }
    }
   
void led06()        //模式6:四四点亮
    {
      unsigned char h="5",i;


      while(h--)
      {
        for(i=0;i<2;i++)            //四四顺序点亮
        LED_06(i); 
  PORTB=0XFF; 
      }
    }
   
void led07()         //模式7:全部点亮熄灭
    {
      unsigned char h="5";
      while(h--)
     {
        LED_on();
        LED_off();
     }
  PORTB="0XFF";
    }


4、delay.c


/*******************************
Platform : AVR mega16学习板(www.iccavr.com
function :延时函数
Clock F  : 3.6864M
Software : ICCAVR7.14C
Author   : 林夕依然
Version  : 09.02.25
comments :
1、两种方式实现延时
********************************/


/*---------------------------------------------------------------------------------
     延时程序计算方法
     计数个数j = 延时时间/6*晶振频率 - 1
---------------------------------------------------------------------------------*/


#define uchar unsigned char
#define uint unsigned int


//方式一:
void Delay()                       
    {
    uchar a, b, c;
    for (a = 1; a; a++)
        for (b = 1; b; b++)
            for (c = 0; c<10; c++)  //循环次数=255*255*10
          ;
    }


//方式二:1ms延时,准确性较Delay();高
void DelayMs(uint i)               
   {
    while(i--)
    {                         
     uint j;               
        for(j=1;j<=613;j++)  
      ;              
    }                      
   }

文章评论0条评论)

登录后参与讨论
我要评论
0
13
关闭 站长推荐上一条 /2 下一条