一、使用proteus绘制简单的电路图,用于后续仿真
二、编写程序
/********************************************************************************************************************
---- @Project: USART
---- @File: main.c
---- @Edit: ZHQ
---- @Version: V1.0
---- @CreationTime: 20200713
---- @ModifiedTime: 20200713
---- @Description:
---- 波特率是:9600 。
---- 按一次按键S1,单片机就往上位机发送以下一串数据:eb 00 55 01 00 00 00 00 41
---- 单片机: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_send_size 20 /*串口发送数据的缓冲区数组大小*/
#define const_voice_short 40 /*蜂鸣器短叫的持续时间*/
#define const_key_time1 20 /*按键去抖动延时的时间*/
/*——————变量函数定义及声明——————*/
/*蜂鸣器的驱动IO口*/
sbit BEEP = P2^7;
/*LED*/
sbit LED = P3^5;
/*按键*/
sbit Key_S1 = P0^0;
sbit Key_Gnd = P0^4;
unsigned char ucSendregBuf[const_send_size]; /*接收串口中断数据的缓冲区数组*/
/*为串口计时器多增加一个原子锁,作为中断与主函数共享数据的保护*/
unsigned char ucVoiceLock = 0; /*蜂鸣器鸣叫的原子锁*/
unsigned int uiVoiceCnt = 0; /*蜂鸣器鸣叫的持续时间计数器*/
unsigned char ucKeySec = 0; /*被触发的按键编号*/
unsigned int uiKeyTimeCnt1 = 0; /*按键去抖动延时计数器*/
unsigned char ucKeyLock1 = 0; /*按键触发后自锁的变量标志*/
/**
* @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)
{
ET0 = 1;/*允许定时中断*/
TR0 = 1;/*启动定时中断*/
TR1 = 1;
ES = 1; /*允许串口中断*/
EA = 1;/*开总中断*/
}
/**
* @brief 初始化函数
* @param 无
* @retval 初始化单片机
**/
void Init(void)
{
LED = 0;
BEEP = 1;
Key_Gnd = 0;
Init_T0();
Init_USART();
}
/**
* @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 ucSendData * @retval 在发送一串数据中,每个字节之间必须添加一个延时,用来等待串口发送完成。 * 不增加延时,单单靠发送完成标志位来判断还是容易出错,在51,PIC单片机中都是这么做。 * 在stm32单片机中,可以不增加延时,直接靠单片机自带的标志位来判断就很可靠。 **/ void eusart_send(unsigned char ucSendData) { ES = 0; /*关串口中断*/ TI = 0; /*清零串口发送完成中断请求标志*/ SBUF = ucSendData; /*发送一个字节*/ Delay_Short(400); /*每个字节之间的延时。延时的大小请根据实际项目来调整*/ TI = 0; /*清零串口发送完成中断请求标志*/ ES = 1; /*允许串口中断*/ } /** * @brief 按键扫描函数 * @param 无 * @retval 放在定时中断里 **/ void key_scan(void) { if(Key_S1 == 1) /*IO是高电平,说明按键没有被按下,这时要及时清零一些标志位*/ { ucKeyLock1 = 0; /*按键自锁标志清零*/ uiKeyTimeCnt1 = 0; /*按键去抖动延时计数器清零*/ } else if(ucKeyLock1 == 0) /*有按键按下,且是第一次被按下*/ { uiKeyTimeCnt1 ++; /*累加定时中断次数*/ if(uiKeyTimeCnt1 > const_key_time1) { uiKeyTimeCnt1 = 0; ucKeyLock1 = 1; /*自锁按键置位,避免一直触发*/ ucKeySec = 1; } } } /** * @brief 按键服务的应用程序 * @param 无 * @retval 无 **/ void key_service(void) { unsigned int i; switch(ucKeySec) /*按键服务状态切换*/ { case 1: ucSendregBuf[0] = 0xeb; /*把准备发送的数据放入发送缓冲区*/ ucSendregBuf[1] = 0x00; ucSendregBuf[2] = 0x55; ucSendregBuf[3] = 0x01; ucSendregBuf[4] = 0x00; ucSendregBuf[5] = 0x00; ucSendregBuf[6] = 0x00; ucSendregBuf[7] = 0x00; ucSendregBuf[8] = 0x41; for(i = 0; i <= 8; i ++) { eusart_send(ucSendregBuf[i]); /*发送一串数据给上位机*/ } ucVoiceLock = 1; /*原子锁加锁,保护中断与主函数的共享数据*/ uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ ucVoiceLock = 0; /*原子锁解锁*/ ucKeySec = 0; /*响应按键服务处理程序后,按键编号清零,避免一致触发*/ break; } } /** * @brief 定时器0中断函数 * @param 无 * @retval 无 **/ void ISR_T0(void) interrupt 1 { TF0 = 0; /*清除中断标志*/ TR0 = 0; /*关中断*/ /* * 此处多增加一个原子锁,作为中断与主函数共享数据的保护 */ if(ucVoiceLock == 0) /*原子锁判断*/ { if(uiVoiceCnt != 0) { uiVoiceCnt --; BEEP = 0; } else { ; BEEP = 1; } } key_scan(); TL0 = T1MS; /*initial timer0 low byte*/ TH0 = T1MS >> 8; /*initial timer0 high byte*/ TR0 = 1; /*开中断*/ } /** * @brief 串口接收数据中断 * @param 无 * @retval 无 **/ void usart_receive(void) interrupt 4 { if(RI == 1) { RI = 0; } else { TI = 0; } } /*————————————主函数————————————*/ /** * @brief 主函数 * @param 无 * @retval 实现LED灯闪烁 **/ void main() { /*单片机初始化*/ Init(); /*延时,延时时间一般是0.3秒到2秒之间,等待外围芯片和模块上电稳定*/ Delay_Long(100); /*单片机外围初始化*/ Init_Peripheral(); while(1) { key_service(); /*按键服务的应用程序*/ } } 三、仿真实现
上一篇:51单片机实现通过串口用计数延时方式发送一串数据
下一篇:51单片机实现在串口接收中断里即时解析数据头的特殊程序框架
推荐阅读最新更新时间:2024-11-06 13:42