》》点此进入 http://bbs.armavr.com/ ARM-AVR嵌入式开发论坛
【相关实验】
实验一:流水灯实验(八种LED点亮模式)
实验二:有源蜂鸣器驱动实验
实验四:键盘扫描+8种LED亮灭模式控制
*********************************************************************
2008年年末,初步的学习了AVR单片机的USART模块(实验20),现在看来,当时的理解不深入不全面,没能从抓住它的要点。今天从新的复习了一下,详细的阅读了datasheet,感觉收益颇深,之前不能理解的概念,今天突然的明了了。看来:“书读百遍,其意自现”的古语真是有道理啊。
本次的综合实验,参考了www.avrvi.com的部分程序。现在分享出来,供朋友们参考,希望朋友们多提意见,批评指正。
一、硬件电路
1、LED电路
2、MAX232电路
3、串口调试助手数据接收
二、程序结构
三、程序代码
1、main.c主函数
/******************************************************************************
Platform: AVR mega16学习板(www.iccavr.com)
Project : 实验二八:USART综合实验
Clock F : 3.6864MHz
Software: ICCAVR7.14C
Author : 林夕依然
Version : 09.03.19
Updata :
comments:
1、以学习板LED,MAX232为硬件电路。
2、接收发自电脑的数据,根据收到的对应数据,先将收到的数据原样返回电脑,并执行
收到的数据所对应的操作。
3、用串口助手工具调试,理解串口通讯协议。
4、两种串口初始化方法均可使用。
5、参考:AVR与虚拟仪器 http://www.avrvi.com 古欣AVR mega16 串口测试
problem :
1、一个汉字有两个字节组成
2、使用USART_Transmits02(*a) 函数时,电脑接收乱码
*******************************************************************************/
// ICC-AVR application builder : 2007-5-20 17:21:25
// Target : M16
// Crystal: 3.6864Mhz
// AVR mega16 串口测试
// AVR与虚拟仪器 http://www.avrvi.com 古欣
#include <iom16v.h>
#include <macros.h>
const unsigned char buffer[]="2009年03月19日23:55";
const unsigned char buffer1[]="QQ:605987969";
const unsigned char buffer2[]="欢迎访问http://blog.ednchina.com/xiantaozeng/";
void main(void)
{
unsigned char i="0",tmp=0;
port_init(); //端口初始化,关闭LED
//Usart_init01(); //初始化串口方式1,波特率9600 (测试可用)
Usart_init02(9600); //初始化串口方式2,波特率9600 (测试可用)
for(i=0;i<20;i++) //发送数组里面的字符串:实验日期和时间
{
USART_Transmit(buffer);
}
newline();//换行
while(1)
{
if(UCSRA&(1<<RXC)) //如果接收缓存区有数据
{
tmp="USART"_Receive(); //接收数据
USART_Transmit(tmp); //发送数据
if(tmp=='a') //对接收到的数据进行,如果是a,再发一个OK回来
{
newline();//换行
USART_Transmit('O');
USART_Transmit('K');
newline();//换行
}
if(tmp=='A') //对接收到的数据进行,如果是A,再发一个Hello回来
{
newline();//换行
USART_Transmits01();
newline();//换行
}
if(tmp=='q'|tmp=='Q') //检测接收到的数据,如果是q或Q,则将QQ号码返回给电脑
{
newline();//换行
for(i=0;i<12;i++) //发送数组里面的字符串
{
USART_Transmit(buffer1);
}
newline();//换行
}
if(tmp=='w'|tmp=='W') //检测接收到的数据,如果是w或W,则将EDN博客网址发给电脑
{
newline();//换行
for(i=0;i<45;i++) //发送数组里面的字符串:http://blog.ednchina.com/xiantaozeng/
{
USART_Transmit(buffer2);
}
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 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) //初始化串口方式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( unsigned int baud )//初始化串口方式2,并设置波特率
{
unsigned int tmp;
tmp= F_CPU/baud/16-1; //设置波特率,见M16_cn中文P135:Table60波特率计算公式
UBRRH = (unsigned char)(tmp>>8);
UBRRL = (unsigned char)tmp;
UCSRB = (1<<RXEN)|(1<<TXEN); //接收器与发送器使能
UCSRC = (1<<URSEL)|(1<<USBS)|(1<<UCSZ0)|(1<<UCSZ1);//帧格式:8个数据位,2个停止位
}
//下面两个函数直接从数据手册上拷贝过来的
// 数据发送【发送5 到8 位数据位的帧】
void USART_Transmit( unsigned char data )
{
while ( !( UCSRA & (1<<UDRE)) ) ; //等待发送缓冲器为空
UDR = data; // 将数据放入缓冲器,发送数据
}
// 数据接收【以5 到8 个数据位的方式接收数 据帧】
unsigned char USART_Receive( void )
{
while ( !(UCSRA & (1<<RXC)) ); // 等待接收数据
return UDR; // 从缓冲器中获取并返回数据
}
//连续发送字符
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(unsigned char *ptr)//字符串
{
while (*ptr)
{
USART_Transmit(*ptr);
*ptr++;
}
newline();
}
void newline() //换行
{
USART_Transmit(0x0d); //发送一个回车
USART_Transmit(0x0a); //发送一个换行
}
void blank() //空格
{
USART_Transmit(0x20);
}
3、led.c LED函数
/*******************************
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++)
;
}
}
用户160973 2010-11-28 21:46
tengjingshu_112148725 2009-3-23 09:24