完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
一、实验目的 1.掌握单片机串行口通信的程序设计,及简易三线式通讯的方法。
2.了解实现串行通讯的硬环境、数据格式的协议、数据交换的协议。 3.学习串口通讯的中断方式的程序编写方法。 4.进一步熟悉利用 PROTEUS、Keil uVision5 等软件进行单片机系统仿真设计的方法。 二、实验任务 1.基本任务 (1)已知甲机接 8 个开关,乙机接 8 个发光二极管,利用它们的串口方式 1,波 特率自定义,实现:将甲机中 8 个开关所代表的数据传送到乙机,并在乙机的 8 个 LED 灯显示。请在 Proteus 中画出电路原理图,并编写程序仿真实现上述功能。 (2)已知单片机的 P0 口接了 8 个发光二极管 LED0~LED7,现要求通过单片机的 串口收发上位机的命令,实现对这 8 个发光二极管的控制。PC 端采用串口调试程序进 行数据发送(如使用 stc-isp 烧写软件向单片机发送“88 FB AF XX FC FC”6 个字节的 命令,其中“88 FB AF”及“FC FC”为数据的帧头和帧尾,“XX”为 00~07 数据。 )单片机 使用串口中断进行数据接收,同时需要判断帧头和帧尾的正确性。判断帧头和帧尾完毕 后,若正确的话再判断“XX” 数据,对应“XX” 数据对 LED0~LED7 进行点亮、熄灭控 制;若不正确丢掉数据, 转入等待接收。 请在 Proteus 中画出电路原理图,并编写程 序仿真实现上述功能。 2.拓展任务 在以上基本任务 1 的基础上,奇校验,实现甲机和乙机的全双工通信,即甲机和乙 机都分别接 8 个开关和 8 个发光二极管,甲机 8 个开关所代表的数据能传送到乙机并在 乙机的 8 个 LED 灯显示,同时乙机 8 个开关所代表的数据能传送到甲机并在甲机的 8 个 LED 灯显示,若校验出错则指示灯(自定义)闪烁。请在 Proteus 中画出电路原理图, 并编写程序仿真实现上述功能。 //-----------------------发送端---------------------------// #include "STC15.H" bit busy=0; //-----------------------串口初始化子函数-------------------------// void Uart1_Init(void) //9600bps@11.0592MHz { SCON = 0x40; //8位数据,可变波特率 方式1 AUXR |= 0x40; //定时器1时钟为Fosc,即1T AUXR &= 0xFE; //串口1选择定时器1为波特率发生器 TMOD &= 0x0F; //设定定时器1为16位自动重装方式 TL1 = 0xE0; //设定定时初值 TH1 = 0xFE; //设定定时初值 ET1 = 0; //禁止定时器1中断 TR1 = 1; //启动定时器1 ES = 1; //启动串口中断 } //-----------------------数据发送子函数---------------------------// void SendData(unsigned char dat) { while(busy); SBUF=dat; busy=1; } //---------------------------中断函数------------------------------// void UART1_isr (void) interrupt 4 { if(TI) { TI=0; //清除标志位 busy=0; //清除忙标志位 } } //---------------------------主函数------------------------------// void main() { Uart1_Init(); //串口初始化 EA=1; //打开总中断 while(1) { SendData(P1); //发送P1口数值 } } //-----------------------接收端---------------------------// #include "STC15.H" unsigned int temp; //-----------------------串口初始化子函数-------------------------// void Uart1_Init(void) //9600bps@11.0592MHz { SCON = 0x50; //8位数据,可变波特率 REN=1处于接受状态 AUXR |= 0x40; //定时器1时钟为Fosc,即1T AUXR &= 0xFE; //串口1选择定时器1为波特率发生器 TMOD &= 0x0F; //设定定时器1为16位自动重装方式 TL1 = 0xE0; //设定定时初值 TH1 = 0xFE; //设定定时初值 ET1 = 0; //禁止定时器1中断 TR1 = 1; //启动定时器1 ES = 1; //启动串口中断 } //-------------------------中断函数------------------------------// void UART1_isr (void) interrupt 4 { if(RI) { RI=0; //标志位清0 temp=SBUF; //数据暂存 P0=temp; //P0接收发送端数据 } } //---------------------------主函数------------------------------// void main() { Uart1_Init(); //串口初始化 EA=1; //打开总中断 while(1); } #include "stc15.h" #define uchar unsigned int //对数据类型进行声明定义 volatile bit Flag=0; uchar i,val; uchar arr[6]; //-----------------------串口初始化子函数-------------------------// void Uart1_init() //9600bps@11.0592MHz { PCON &= 0x7F; //波特率不加倍控制/帧错误检测 SCON = 0x50; //8位数据,可变波特率 AUXR |= 0x40; //定时器1时钟为Fosc,即1T AUXR &= 0xFE; //串口1选择定时器1为波特率发生器 TMOD &= 0x0F; //设定定时器1为16位自动重装方式 TL1 = 0xE0; //设定定时初值 TH1 = 0xFE; //设定定时初值 ET1 = 0; //禁止定时器1中断 TR1 = 1; //启动定时器1 ES=1; // 串口1中断打开 EA=1; //全局中断使能 } //---------------------------中断函数------------------------------// void Uart1_INT() interrupt 4 { ES=0; //串口1中断关闭 if(RI) { Flag=1; //接收到数据,接收标识符有效 RI=0; //串口接收标志位清0 arr=SBUF; //将接收到的数据赋给数组中判断 if(arr==0x88) //判断数组 { arr[0]=arr; i=0; } i++; if(i==6) { i=0; if(arr[0]==0x88&&arr[1]==0xFB&&arr[2]==0xAF&&arr[4]==0xFC&&arr[5]==0xFC) { val=arr[3]; switch (val) { case 0x00:P0=0XFE;break; case 0x01:P0=0XFD;break; case 0x02:P0=0XFB;break; case 0x03:P0=0XF7;break; case 0x04:P0=0XEF;break; case 0x05:P0=0XDF;break; case 0x06:P0=0XBF;break; case 0x07:P0=0X7F;break; } } } } ES=1; // 串口1中断打开 } //---------------------------主函数------------------------------// void main() { Uart1_init(); //串口初始化 while(1); //循环运行 } #include "stc15.h" #include "intrins.h" volatile bit Flag=1; //---------------------------延时函数------------------------------// void Delay150ms() //@11.0592MHz { unsigned char i, j, k; _nop_(); _nop_(); i = 7; j = 78; k = 167; do { do { while (--k); } while (--j); } while (--i); } //-----------------------串口初始化子函数-------------------------// void Uart1_Init(void) //9600bps@11.0592MHz { SCON = 0x90; //9位数据,方式2,可变波特率,带TB8/RB8奇偶校验位 AUXR |= 0x40; //定时器1时钟为Fosc,即1T AUXR &= 0xFE; //串口1选择定时器1为波特率发生器 TMOD &= 0x0F; //设定定时器1为16位自动重装方式 TL1 = 0xE0; //设定定时初值 TH1 = 0xFE; //设定定时初值 ET1 = 0; //禁止定时器1中断 TR1 = 1; //启动定时器1 ES = 1; //使能串口中断 EA=1; //全局中断使能 } //-------------------------数据发送函数-----------------------------// /********************************************************************* * 由于PSW中的P可以表达累加器ACC中“1”的个数奇偶性,P=1,A中“1”的个数为 * * 奇数,P=0,A中“1”的个数为偶数 * *********************************************************************/ void Send_Data(unsigned char dat) { ACC=dat; //将数据赋给累加器ACC TB8=P; //发送从累加器得到的第9位数据 SBUF=dat; //发送数据到数据缓冲器 while(TI==0);//当TI标志位等于零时 TI=0; //TI标志位清零 } //-------------------------数据传送函数-----------------------------// void UART1_Puts(void) { if(Flag) { ES=0; //串口1中断关闭 Send_Data(P1); //发送P1接收到的数据 ES=1; //串口1中断开启 Flag=0; //清除接收标识符 } } //---------------------------中断函数------------------------------// void Uart1_Isr(void) interrupt 4 { ES=0; //串口1中断关闭 if(RI) //RI为1,接收数据 { RI=0; //RI标志位清零 Flag=1; //接收到数据,接收标识符有效 if(RB8==1) //接收第9位数据校验结果是否为奇数 { P0=SBUF; //将接收到的数据赋给P0端 } else //校验结果不为奇数时,出错执行P0端LED全亮全灭 { P0=0x00; Delay150ms(); P0=0xFF; Delay150ms(); } } if(TI) //TI为1,发送数据 { TI=0; //TI标志位清零 } ES=1; //串口1中断打开 } //---------------------------主函数------------------------------// void main() { Uart1_Init(); //串口初始化 while(1) //循环运行 { UART1_Puts(); //数据传送 } } |
|
|
|
只有小组成员才能发言,加入小组>>
2528 浏览 0 评论
1117浏览 2评论
725浏览 1评论
477浏览 0评论
225浏览 0评论
370浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-4 01:41 , Processed in 1.212934 second(s), Total 51, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号