程序设计目标及程序运行效果说明
程序设计目标:本实验实现的是红外单工方简单上下位机串口数据的发送与接收。单片机通过按键2、3调整发送的数据(0~F),按键1控制数据发送给上位机,并在串口助手的接收数据缓存区显示;上位机设定发送缓存区数据发送数据给单片机单片机将值显示在数码管。
程序运行效果说明:上位机向单片机发送数据:在发送缓冲区显示要发送的数据,按下按键1数据发送到单片机,并在数码管上显示相应的数据;下位机向上位机发送数据:在单片机数码管上显示要发送的数据,可以通过按键2、3进行调整,按下按键1数据发送到上位机,在接受缓冲区显示接收到的数据。
程序相关电路及工作原理说明
说明:当RXD、TXD为低电平时,对应的LED灯亮起
1.电路工作原理
单片机集成了USB转串口模块,对应使用RXD线接收数据,用TXD发送数据。每个串口由2个数据缓冲器(相互独立1收1发)、一个移位寄存器(一字节数据一位一位发送出去)、一个串行控制器和一个波特率发生器(这个比较重要,结合相关的定时器)组成。对应发送、接收数据完成(RI、TI硬件置1)都会触发串口中断,但是无法确定是哪个触发的,所以在串口中断中我们要判断是接收数据产生的中断还是发送数据产生的中断,对于发送数据产生的中断,我们要软件将TI清0,并将数据就绪标志清0,允许下一字节数据发送,发送数据函数中通过while循环,等待发送数据准备就绪,完了将就绪的数据复制给SBUF;对于接收数据产生的中断,我们要软件将RI清0,并从SBUF中读取数据。
下图为80C51串行口的结构:
SCON:串行口控制寄存器
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
字节地址:98H | SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
SM0、SM1:工作方式选择位
SM0 | SM1 | 方式 | 说明 | 波特率 |
---|---|---|---|---|
0 | 0 | 0 | 移位寄存器 | fosc/12 |
0 | 1 | 1 | 10位异步收发器(8位数据) | 可变 |
1 | 0 | 2 | 11位异步收发器(9位数据) | fosc/64或fosc/32 |
1 | 1 | 3 | 11位异步收发器(9位数据) | 可变 |
SM2:多机通信控制位,主要用于方式2和方式3。当接收机的SM2=1时可以利用收到的RB8来控制是否激活RI(RB8=0时不激活RI,收到的信息丢弃;RB8=1时收到的数据进入SBUF,并激活RI,进而在中断服务中将数据从SBUF读走)。当SM2=0时,不论收到的RB8为0和1,均可以使收到的数据进入SBUF,并激活RI。
REN:允许串行接收位。由软件置REN=1,则启动串行口接收数据;若软件置REN=0,则禁止接收。
TB8:在方式2或方式3中,是发送数据的第九位,可以用软件规定其作用。可以用作数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志位。
RB8:在方式2或方式3中,是接收到数据的第九位,作为奇偶校验位或地址帧/数据帧的标志位。在方式1时,若SM2=0,则RB8是接收到的停止位。
TI:发送中断标志位。在方式0时,当串行发送第8位数据结束时,或在其它方式,串行发送停止位的开始时,由内部硬件使TI置1,向CPU发中断申请。在中断服务程序中,必须用软件将其清0,取消此中断申请。
RI:接收中断标志位。在方式0时,当串行接收第8位数据结束时,或在其它方式,串行接收停止位的中间时,由内部硬件使RI置1,向CPU发中断申请。也必须在中断服务程序中,用软件将其清0,取消此中断申请。
PCON(电源控制寄存器):其中的SMOD(PCON[7])与串行工作有关——对方式1,2,3,当SMOD为1时,波特率提高一倍。
PCON:
SMOD | SMOD0 | LVDF | POF | GF1 | GF0 | PD | IDL |
---|
2.RS232通信原理
RS是“推荐标准”的缩写,232为标识号,C表示修改次数。标准设有25条信号线,包括一个主通道和一个辅助通道。通常 RS-232 接口以9个引脚(DB-9) 或是25个引脚 (DB-25) 的型态出现。
串口通信的传输格式:串行通信中,线路空闲时,线路的TTL电平总是高,经反向RS232的电平总是低。一个数据的开始RS232线路为高电平,结束时Rs232为低电平。数据总是从低位向高位一位一位的传输。示波器读数时,左边是数据的高位。
测试方法
(1)按照“工程建立及下载到开发板整个流程指导.doc”文件将当前目录的Hex文件下载到开发版;
(2) 默认最左边数码管显示00;
(3)程序下载完后默认是留在“程序文件”界面,我们点击“串口助手”选项,对串口、波特率、校验位、停止位进行设置,因为本实验是8位波特率可变的串口通信,所以无需设置校验位、停止位,本实验采用的波特率是9600;
(4) 点击“打开串口”按钮,打开串口;
(5) 设置完后选择“文本模式”或者“HEX模式”,进行数据的发送与接收。
(6)在发送缓存区输入“05”,点击“发送数据”按钮,完成上位机向单片机发送数据,在单片机数码管上显示数字“05”;
(7)通过key2或者key3调整数值(数码管会显示出来)如“0c”,按下key1,完成单片机向上位机发送数据;此时在接收缓冲区显示“0c”。
代码如下:
#include<STC15F2K60S2.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define cstKeyMaxNum 100//按键抖动次数
sbit sbtKey1=P3^2;//启动发送
sbit sbtKey2=P3^3;//数字减少
sbit sbtKey3=P1^7;//按键抖动次数
sbit sbtLedSel=P2^3;
uchar ucT100usTimes;
uint uiKey1Cnt;//按键1记数
uint uiKey2Cnt;//按键2记数
uint uiKey3Cnt;//按键3记数
uint uiKeyAllCnt;//按键总的抖动次数
bit btT1msFlag;//1ms的标志
bit btKey1Current;//key1当前的状态
bit btKey1Past;//key1前一个状态
bit btKey2Current;//key2当前的状态
bit btKey2Past;//key2前一个状态
bit btKey3Current;//key3当前的状态
bit btKey3Past;//key3前一个状态
bit btUart1SendBusy=0;
uchar ucDateTmp;//传输数据暂存
uchar ucDateDigState;
uchar arrSegSelect[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void Uart1_Init()//串口1初始化函数
{
AUXR=0X80;
SCON|=0X50;
TL1=0xE0;
TH1=0xFE;
AUXR|=0X40;
RI=0;
TI=0;
TR1=1;
ES=1;//串口中断允许位
EA=1;//总中断允许位
PS=1;//串口1中断优先级
}
void Init()
{
P3M0=0x00;
P3M1=0x00;
P2M0=0xff;
P2M1=0x00;
P0M0=0xff;
P0M1=0x00;
TMOD=0x01;//定时器0,方式1
ET0=1;//开启定时器中断
TH0=(65535-1000)/256;
TL0=(65535-1000)%256;
TR0=1;//启动定时器
Uart1_Init();//外部中断;低优先级
ucDateTmp=0x00;
sbtLedSel=0;
btT1msFlag=0;
//初始化所有按键的当前状态、前一个状态
btKey1Current=1;//key1当前状态
btKey1Past=1;//key1前一个状态
btKey2Current=1;//key2当前状态
btKey2Past=1;//key2前一个状态
btKey3Current=1;//key3当前状态
btKey3Past=1;//key3前一个状态
uiKey1Cnt=0x80+cstKeyMaxNum/3*2;//加上0x80防止uiKey1Cnt为负数
uiKey2Cnt=0x80+cstKeyMaxNum/3*2;
uiKey3Cnt=0x80+cstKeyMaxNum/3*2;
uiKeyAllCnt=cstKeyMaxNum;
}
void T0_Process()interrupt 1
{
TH0=(65535-100)/256;//定时器初始值
TL0=(65535-100)%256;
ucT100usTimes++;
if(ucT100usTimes==10)//中断10次对应1ms
{
ucT100usTimes=0;
btT1msFlag=1;
}
ucDateDigState++;
if(ucDateDigState==2)
ucDateDigState=0;
P0=0;
switch(ucDateDigState)
{
case 0:P2=0x00;P0=arrSegSelect[ucDateTmp / 16];break;
case 1:P2=0x01;P0=arrSegSelect[ucDateTmp%16];break;
}
}
void SendData(unsigned char dat)//发送数据函数
{
while(btUart1SendBusy);//发送单个字符给UART1以发送到PC机
btUart1SendBusy=1;
SBUF=dat;
}
void Uart1_Process()interrupt 4 using 1//串口1中断处理函数
{
if(RI)//接受完数据后,RI自动置1
{
RI=0;
ucDateTmp=SBUF;
}
if(TI)//发送完数据后,TI自动置1
{
TI=0;
btUart1SendBusy=0;
}
}
void main()
{
Init();
while(1)
{
if(btT1msFlag)
{
btT1msFlag=0;
if(sbtKey1==0)
uiKey1Cnt--;
if(sbtKey2==0)
uiKey2Cnt--;
if(sbtKey3==0)//按键是按下状态
uiKey3Cnt--;
uiKeyAllCnt--;//总的次数减1
if(uiKeyAllCnt==0)
{
if(uiKey1Cnt<0x80)
{
btKey1Current=0;
if(btKey1Past==1)//下降沿(按键做动作)
{
btKey1Past=0;
SendData(ucDateTmp);
}
}
if(uiKey1Cnt>=0x80)
{
btKey1Current=1;
if(btKey1Past==0)
btKey1Past=1;//上升沿(假设不做动作那就继续)
}
if(uiKey2Cnt<0x80)
{
btKey2Current=0;
if(btKey2Past==1)//下降沿(按键做动作)
{
btKey2Past=0;
ucDateTmp--;
}
}
if(uiKey2Cnt>=0x80)
{
btKey2Current=1;
if( btKey2Past==0)
btKey2Past=1;//上升沿(假设不做动作那就继续)
}
if(uiKey3Cnt<0x80)
{
btKey3Current=0;
if(btKey3Past==1)//下降沿(按键做动作)
{
btKey3Past=0;
ucDateTmp++;
}
}
if(uiKey3Cnt>=0x80)
{
btKey3Current=1;
if(btKey3Past==0)
btKey3Past=1;//上升沿(假设不做动作那就继续)
}
//新一轮的判断
uiKey1Cnt=0x80+cstKeyMaxNum/3*2;
uiKey2Cnt=0x80+cstKeyMaxNum/3*2;
uiKey3Cnt=0x80+cstKeyMaxNum/3*2;
uiKeyAllCnt=cstKeyMaxNum;
}
}
}
}