历史上的今天
今天是:2024年11月08日(星期五)
2021年11月08日 | 51单片机实现从机的串口收发
2021-11-08 来源:eefocus
一、使用proteus绘制简单的电路图,用于后续仿真

二、编写程序
/********************************************************************************************************************
---- @Project: USART
---- @File: main.c
---- @Edit: ZHQ
---- @Version: V1.0
---- @CreationTime: 20200717
---- @ModifiedTime: 20200717
---- @Description: 实现功能:
---- 显示和独立按键部分根据数码管显示的程序来改编,用S1,S5,S9,S13作为独立按键。
---- 一共有4个窗口。每个窗口显示一个参数。有两种更改参数的方式:
---- 第一种:按键更改参数:
---- 第8,7,6,5位数码管显示当前窗口,P-1代表第1个窗口,P-2代表第2个窗口,P-3代表第3个窗口,P-4代表第1个窗口。
---- 第4,3,2,1位数码管显示当前窗口被设置的参数。范围是从0到9999。S1是加按键,按下此按键会依次增加当前窗口的参数。S5是减按键,按下此按键会依次减少当前窗口的参数。S9是切换窗口按键,按下此按键会依次循环切换不同的窗口。S13是复位按键,当通讯超时蜂鸣器报警时,可以按下此键清除报警。
----
---- 第二种:通过串口来更改参数:
---- 波特率是:9600.
---- ---- 通讯协议:EB 00 55 GG 00 02 XX XX CY
---- 其中第1,2,3位EB 00 55就是数据头
---- 其中第4位GG就是数据类型。01代表更改参数1,02代表更改参数2,03代表更改参数3,04代表更改参数4,
---- 其中第5,6位00 02就是有效数据长度。高位在左,低位在右。
---- 其中从第7,8位XX XX是被更改的参数。高位在左,低位在右。
---- 第9位CY是累加和,前面所有字节的累加。
---- 一个完整的通讯必须接收完4串数据,每串数据之间的间隔时间不能超过10秒钟,否则认为通讯超时出错引发蜂鸣器报警。如果接收到得数据校验正确,
---- 则返回校验正确应答:eb 00 55 f5 00 00 35,
---- 否则返回校验出错应答::eb 00 55 fa 00 00 3a。
---- 系统处于待机状态时,LED灯一直亮,
---- 系统处于非待机状态时,LED灯闪烁,
---- 系统处于通讯超时出错状态时,LED灯闪烁,并且蜂鸣器间歇鸣叫报警。
----
---- 通过电脑的串口助手,依次发送以下测试数据,将会分别更改参数1,参数2,参数3,参数4。注意,每串数据之间的时间最大不能超过10秒,否则系统认为通讯超时报警。
---- 把参数1更改为十进制的1: eb 00 55 01 00 02 00 01 44
---- 把参数2更改为十进制的12: eb 00 55 02 00 02 00 0c 50
---- 把参数3更改为十进制的123: eb 00 55 03 00 02 00 7b c0
---- 把参数4更改为十进制的1234:eb 00 55 04 00 02 04 d2 1c
---- 单片机:AT89C52
********************************************************************************************************************/
#include "reg52.h"
/*——————宏定义——————*/
#define FOSC 11059200L
#define BAUD 9600
#define T1MS (65536-FOSC/12/500) /*0.5ms timer calculation method in 12Tmode*/
#define const_key_time1 9 /*按键去抖动延时的时间*/
#define const_key_time2 9 /*按键去抖动延时的时间*/
#define const_key_time3 9 /*按键去抖动延时的时间*/
#define const_key_time4 9 /*按键去抖动延时的时间*/
#define const_led_0_5s 32 /*大概0.5秒的时间*/
#define const_led_1s 64 /*大概1秒的时间*/
#define const_send_time_out 640 /*通讯超时出错的时间 大概10秒*/
#define const_rc_size 20 /*接收串口中断数据的缓冲区数组大小*/
#define const_receive_time 5 /*如果超过这个时间没有串口数据过来,就认为一串数据已经全部接收完,这个时间根据实际情况来调整大小*/
#define const_send_size 10 /*串口发送数据的缓冲区数组大小*/
#define const_voice_short 20 /*蜂鸣器短叫的持续时间*/
/*——————变量函数定义及声明——————*/
/*蜂鸣器的驱动IO口*/
sbit BEEP = P2^7;
/*LED*/
sbit LED = P3^5;
/*按键*/
sbit Key_S1 = P0^0; /*对应S1键,加键*/
sbit Key_S2 = P0^1; /*对应S5键,减键*/
sbit Key_S3 = P0^2; /*对应S9键,切换窗口*/
sbit Key_S4 = P0^3; /*对应S13键,复位*/
sbit Key_Gnd = P0^4;
/*数码管*/
sbit Dig_Hc595_Sh = P2^0;
sbit Dig_Hc595_St = P2^1;
sbit Dig_Hc595_Ds = P2^2;
unsigned char ucSendregBuf[const_send_size]; /*发送的缓冲区数组*/
unsigned int uiSendCnt = 0; /*用来识别串口是否接收完一串数据的计时器*/
unsigned char ucSendLock = 1; /*串口服务程序的自锁变量,每次接收完一串数据只处理一次*/
unsigned int uiRcregTotal = 0; /*代表当前缓冲区已经接收了多少个数据*/
unsigned char ucRcregBuf[const_rc_size]; /*接收串口中断数据的缓冲区数组*/
unsigned int uiRcMoveIndex = 0; /*用来解析数据协议的中间变量*/
unsigned char ucSendCntLock = 0; /*串口计时器的原子锁*/
unsigned char ucRcType = 0; /*数据类型*/
unsigned int uiRcSize = 0; /*数据长度*/
unsigned char ucRcCy = 0; /*校验累加和*/
unsigned int uiLedCnt = 0; /*控制Led闪烁的延时计时器*/
unsigned int uiSendTimeOutCnt = 0; /*用来识别接收数据超时的计时器*/
unsigned char ucSendTimeOutLock = 0; /*原子锁*/
unsigned char ucStatus = 0; /*当前状态变量 0代表待机 1代表正在通讯过程 2代表发送出错*/
unsigned char ucKeySec = 0; /*被触发的按键编号*/
unsigned int uiKeyTimeCnt1 = 0; /*按键去抖动延时计数器*/
unsigned char ucKeyLock1 = 0; /*按键触发后自锁的变量标志*/
unsigned int uiKeyTimeCnt2 = 0; /*按键去抖动延时计数器*/
unsigned char ucKeyLock2 = 0; /*按键触发后自锁的变量标志*/
unsigned int uiKeyTimeCnt3 = 0; /*按键去抖动延时计数器*/
unsigned char ucKeyLock3 = 0; /*按键触发后自锁的变量标志*/
unsigned int uiKeyTimeCnt4 = 0; /*按键去抖动延时计数器*/
unsigned char ucKeyLock4 = 0; /*按键触发后自锁的变量标志*/
unsigned int uiVoiceCnt = 0; /*蜂鸣器鸣叫的持续时间计数器*/
unsigned char ucVoiceLock = 0; /*蜂鸣器鸣叫的原子锁*/
unsigned char ucDigShow8; /*第8位数码管要显示的内容*/
unsigned char ucDigShow7; /*第7位数码管要显示的内容*/
unsigned char ucDigShow6; /*第6位数码管要显示的内容*/
unsigned char ucDigShow5; /*第5位数码管要显示的内容*/
unsigned char ucDigShow4; /*第4位数码管要显示的内容*/
unsigned char ucDigShow3; /*第3位数码管要显示的内容*/
unsigned char ucDigShow2; /*第2位数码管要显示的内容*/
unsigned char ucDigShow1; /*第1位数码管要显示的内容*/
unsigned char ucDigDot8; /*数码管8的小数点是否显示的标志*/
unsigned char ucDigDot7; /*数码管7的小数点是否显示的标志*/
unsigned char ucDigDot6; /*数码管6的小数点是否显示的标志*/
unsigned char ucDigDot5; /*数码管5的小数点是否显示的标志*/
unsigned char ucDigDot4; /*数码管4的小数点是否显示的标志*/
unsigned char ucDigDot3; /*数码管3的小数点是否显示的标志*/
unsigned char ucDigDot2; /*数码管2的小数点是否显示的标志*/
unsigned char ucDigDot1; /*数码管1的小数点是否显示的标志*/
unsigned char ucDigShowTemp = 0; /*临时中间变量*/
unsigned char ucDisplayDriveStep = 1; /*动态扫描数码管的步骤变量*/
unsigned char ucWd1Update = 1; /*窗口1更新显示标志*/
unsigned char ucWd2Update = 0; /*窗口2更新显示标志*/
unsigned char ucWd3Update = 0; /*窗口3更新显示标志*/
unsigned char ucWd4Update = 0; /*窗口4更新显示标志*/
unsigned char ucWd = 1; /*本程序的核心变量,窗口显示变量。类似于一级菜单的变量。代表显示不同的窗口。*/
unsigned int uiSetData1 = 0; /*本程序中需要被设置的参数1*/
unsigned int uiSetData2 = 0; /*本程序中需要被设置的参数2*/
unsigned int uiSetData3 = 0; /*本程序中需要被设置的参数3*/
unsigned int uiSetData4 = 0; /*本程序中需要被设置的参数4*/
unsigned char ucTemp1 = 0; /*中间过渡变量*/
unsigned char ucTemp2 = 0; /*中间过渡变量*/
unsigned char ucTemp3 = 0; /*中间过渡变量*/
unsigned char ucTemp4 = 0; /*中间过渡变量*/
void Dig_Hc595_Drive(unsigned char, unsigned char);
/*根据原理图得出的共阴数码管字模表*/
code unsigned char Dig_Table[] =
{
0x3f, /*0 序号0*/
0x06, /*1 序号1*/
0x5b, /*2 序号2*/
0x4f, /*3 序号3*/
0x66, /*4 序号4*/
0x6d, /*5 序号5*/
0x7d, /*6 序号6*/
0x07, /*7 序号7*/
0x7f, /*8 序号8*/
0x6f, /*9 序号9*/
0x00, /*不显示 序号10*/
0x40, /*- 序号11*/
0x73, /*P 序号12*/
};
/**
* @brief 定时器0初始化函数
* @param 无
* @retval 初始化T0
**/
void Init_T0(void)
{
TMOD = 0x01; /*set timer0 as mode1 (16-bit)*/
TL0 = T1MS; /*initial timer0 low byte*/
TH0 = T1MS >> 8; /*initial timer0 high byte*/
}
/**
* @brief 串口初始化函数
* @param 无
* @retval 初始化T0
**/
void Init_USART(void)
{
SCON = 0x50;
TMOD = 0x21;
TH1=TL1=-(FOSC/12/32/BAUD);
}
/**
* @brief 外围初始化函数
* @param 无
* @retval 初始化外围
* 让数码管显示的内容转移到以下几个变量接口上,方便以后编写更上一层的窗口程序。
* 只要更改以下对应变量的内容,就可以显示你想显示的数字。
**/
void Init_Peripheral(void)
{
ucDigDot8 = 0;
ucDigDot7 = 0;
ucDigDot6 = 0;
ucDigDot5 = 0;
ucDigDot4 = 0;
ucDigDot3 = 0;
ucDigDot2 = 0;
ucDigDot1 = 0;
ET0 = 1;/*允许定时中断*/
TR0 = 1;/*启动定时中断*/
TR1 = 1;
ES = 1; /*允许串口中断*/
EA = 1;/*开总中断*/
}
/**
* @brief 初始化函数
* @param 无
* @retval 初始化单片机
**/
void Init(void)
{
LED = 0;
BEEP = 1;
Key_Gnd = 0;
Dig_Hc595_Drive(0x00, 0x00); /*关闭所有经过另外两个74HC595驱动的LED灯*/
Init_T0();
Init_USART();
/*
* 为了保证串口中断接收的数据不丢失,必须设置IP = 0x10,相当于把串口中断设置为最高优先级,
* 这个时候,串口中断可以打断任何其他的中断服务函数实现嵌套,
*/
IP = 0x10; /*把串口中断设置为最高优先级,必须的。*/
}
/**
* @brief 延时函数
* @param 无
* @retval 无
**/
void Delay_Long(unsigned int uiDelayLong)
{
unsigned int i;
unsigned int j;
for(i=0;i for(j=0;j<500;j++) /*内嵌循环的空指令数量*/ { ; /*一个分号相当于执行一条空语句*/ } } } /** * @brief 延时函数 * @param 无 * @retval 无 **/ void Delay_Short(unsigned int uiDelayShort) { unsigned int i; for(i=0;i ; /*一个分号相当于执行一条空语句*/ } } /** * @brief 状态显示的应用程序 * @param 无 * @retval 无 **/ void status_service(void) { if(ucStatus != 0) /*处于非待机的状态,Led闪烁*/ { if(uiLedCnt < const_led_0_5s) /*大概0.5秒*/ { LED = 1; /*前半秒亮*/ if(ucStatus == 2) /*处于发送数据出错的状态,则蜂鸣器间歇鸣叫报警*/ { ucVoiceLock = 1; /*原子锁加锁,保护主函数与中断函数的共享变量uiVoiceCnt*/ uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ ucVoiceLock = 0; /*原子锁解锁,保护主函数与中断函数的共享变量uiVoiceCnt*/ } } else if(uiLedCnt < const_led_1s) { LED = 0; } else { uiLedCnt = 0; /*延时计时器清零,让Led灯处于闪烁的反复循环中*/ } } else { LED = 1; /*处于待机状态,Led一直亮*/ } } /** * @brief 串口发送函数 * @param ucSendData * @retval 在发送一串数据中,每个字节之间必须添加一个延时,用来等待串口发送完成。 * 不增加延时,单单靠发送完成标志位来判断还是容易出错,在51,PIC单片机中都是这么做。 * 在stm32单片机中,可以不增加延时,直接靠单片机自带的标志位来判断就很可靠。
史海拾趣
|
若干高功率微波(HPM)技术已走向成熟,它们正在从工程与制造阶段向战术武器阶段过渡,目前很可能在进攻伊拉克的战斗中看到首次使用微波武器.本文简要介绍美、英、俄三国发展HPM武器技术的计划,评述了几种典型HPM武器研究的重大进展,最后讨论了HPM武器 ...… 查看全部问答> |
|
如果设计稍显复杂,那么对底层细节的过多关注就会成为一种累赘。 试想我们平时在电脑上编写C程序,比如在显示器上输出一行字,我们只用一句printf()即可完成,至于打印命令怎么传到显示芯片上,哪个芯片管脚怎么 变化,又怎么传到显 ...… 查看全部问答> |
|
希望参加《智能家居系统》的网友添加113586004群,在群内讨论问题。 [ 本帖最后由 zhaojun_xf 于 2010-7-31 10:28 编辑 ]… 查看全部问答> |
|
请教各位大大~~~~~关于ARM开发板的选择~~~~~~~~~~ 小弟最近想学RAM,之前一直用的51,不能说精通吧,至少基本的原理和应用算是比较熟悉了 现在想买块开发板,看上面置顶区里有个团购STM32的活动,不知道这块板子怎么样啊? 还有就是STM32在ARM里算是什么样的定位?适不适合像我这 ...… 查看全部问答> |
|
调试时出现的奇怪现象Program exit reached 如图,调试时出现的现象,右边绿色DebugBreak,下边蓝色部分Program exit reached,请问大家遇到过没有?怎么解决,现在烧不进程序了。… 查看全部问答> |
|
今天早上,收到了AT88CK490开发板。先简单的晒板,然后就预备开始测试了,最后再和MAXIM的DS28E15DEMOK开发板做个比较。 简洁的说明和包装 开发板正面,类似TI的EZ430那样的U盘风格。整个板就包含了4颗ATMEL的芯片:一个AT90USB1287 MCU、3个 ...… 查看全部问答> |




