》》点此进入 http://bbs.armavr.com/ ARM-AVR嵌入式开发论坛
【相关实验】
实验一:流水灯实验(八种LED点亮模式)
实验二:有源蜂鸣器驱动实验
实验四:键盘扫描+8种LED亮灭模式控制
【ATMEGA16L】实验二四:四线制LCD1602B驱动实验
【ATMEGA16L】实验二五:八线制LCD1602B驱动实验
***********************************************************************
昨天晚上直到深夜,依然未能使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、串口助手接收数据如下图:
串口助手接收窗口
4、USART_Transmits03(buffer1,10);只不过是“for(i=0;i<20;i++)”程序的另一种写法,也应该是正确的操作,但为什么接收错误呢?请朋友们指点,谢谢。
五、备注:
1、笔记本没有串口,使用了串口转换器,应该不会是串口转换器的缘故吧?
2、波特率,停止位等设置均没问题。
3、单片机采用ATMEGA16L,外部3.6864MHz晶振
*********************************************************************************
回顾了问题之后,接下来就同大家分享:【ATMEGA16L】实验二八:USART串口综合实验(升级版)
一、硬件结构:
二、程序结构:
三、串口助手接收窗口
四、程序代码:
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条评论)
登录后参与讨论