历史上的今天
今天是:2025年11月04日(星期二)
2022年11月04日 | 51单片机入门模板(STC89C52RC)
2022-11-04 来源:csdn
该模板适用于51单片机入门,比较易于理解,包含定时器和串口的操作。
可以在定时器T0中断服务函数和主循环中实现主要功能,在UART中断服务函数(T1定时器)中实现简单的串口通信接收命令的功能。
注:本模板STC89C52RC单片机使用11.0592MHz的晶振,若使用12MHz晶振可修改定时器相关位置
STC89C52RC原理图

模板及分析
1.主要结构
#include unsigned char T0RH = 0; //T0重载值高字节 unsigned char T0RL = 0; //T0重载值低字节 unsigned char RxdByte = 0; //串口接收到的字节 void ConfigTimer0(unsigned int ms); void ConfigUART(unsigned int baud); void main() { EA = 1; //使能总中断 ConfigTimer0(1); //配置为1ms ConfigUART(9600); //配置波特率为9600 while(1) { } } /*配置并启动T0,ms-T0定时时间*/ void ConfigTimer0(unsigned int ms) { } /*串口配置函数,baud-通信波特率*/ void ConfigUART(unsigned int baud) { } /*T0中断服务函数*/ void InterruptTimer0() interrupt 1 { } /*UART中断服务函数*/ void InterruptUART() interrupt 4 { } 2.配置及实现T0中断 先写配置函数ConfigTimer0。要实现每隔一定时间单片机进入T0中断服务函数执行它的功能,首先要确定多久进入一次中断。 我们输入这个函数的参数是ms,需要在函数中转换成单片机实际的工作方式来计算。 STC89C52RC的1个机器周期等于12个时钟周期。单片机的工作周期要用机器周期计算,每过一个单片机的工作周期,定时器的值就从初值向上增加1,在16位定时器模式下直到65536溢出,触发相应中断,进入相应中断服务函数。 以11.0592MHz的晶振为例,先将时钟周期转换为机器周期,ms转换为s计算出所需的计数值。由于定时器是向上计数溢出的,所以要用溢出值减去计数值得出重载值。(假如定时器是向下计数的就不用这步) unsigned long tmp; tmp = 11059200 / 12; //计算所需的计数值 tmp = (tmp * ms) / 1000; tmp = 65536 - tmp; //计算定时器重载值 T0是个16位定时器,分为TH0高8位和TL0低8位,对应重载值也要分开计算。 unsigned char T0RH = 0; //T0重载值高字节 unsigned char T0RL = 0; //T0重载值低字节 T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节 T0RL = tmp; TCON: TMOD: IE: 接下来配置TCON、TMOD和IE这些寄存器。 先把工作模式寄存器TMOD配置为16位定时器模式,然后给TH0、TL0两个8位寄存器赋初值,再配置可位寻址的中断允许寄存器IE,即ET0 = 1,最后配置 定时器/控制器控制寄存器TCON:TR0 = 1 启动T0定时器。 TMOD &= 0xF0; //清零T0控制位 TMOD |= 0x01; //配置T0为模式1 TH0 = T0RH; //加载T0重载值 TL0 = T0RL; ET0 = 1; //使能T0中断 TR0 = 1; //启动T0 最后在T0中断服务函数InterruptTimer0中每次溢出进入中断的时候重新初始化定时器的值,执行功能。 TH0 = T0RH; //重载初值 TL0 = T0RL; ... 3.配置及实现串口中断 串口中断和上面的中断又有所不同。首先,它只能由T1或T2定时器作为“波特率发生器”,T0不可以;其次,定时器的作用是定时检测数据,而不是定时进入中断;再就是串口一般由P3.0(RXD)和P3.1(TXD)担当,因为关于具体通信协议已经由单片机的硬件电路实现了,我们只要懂得如何配置寄存器就可以。 (STC89C52RC只有一个串口,假如要这个单片机既使用串口接收传感器的一些数据,又要把数据通过串口通信传回上位机,一个串口就不够用了,可以用IO口模拟串口,自己写一下串口通信协议的实现,最方便的是用2个串口的单片机) SCON:(串口控制寄存器) 先配置串口为模式1(一字节接收8位),然后配置定时器T1为8位重装载模式,即TL1每次达到256溢出后装载TH1的值.,默认 电源控制器及波特率选择寄存器 PCON = 1, 一个位检测32次,同理,用256减得到T1重载值,也就是控制溢出的时间为约定好波特率时(9600),一个位占用时间的 SCON = 0x50; //配置串口为模式1 TMOD &= 0x0F; //清零T1控制位 TMOD |= 0x20; //配置T1为模式2 TH1 = 256 - (11059200/12/32)/baud; //计算T1重载值 TL1 = TH1; //初始等于重载值 ET1 = 0; //禁止T1中断 ES = 1; //使能串口中断 TR1 = 1; //启动T1 SBUF为串口数据缓冲寄存器,大小为8字节。 当接收一字节数据结束时,RI自动置1,要在中断服务函数中手动归0;TI 同理。然后接收数据,传递执行功能的信息。 /*UART中断服务函数*/ void InterruptUART() interrupt 4 { if (RI) //接收到字节 { RI = 0; //手动清零接收中断标志位 RxdByte = SBUF; //接收到的数据(8位)保留在接收字节变量中 SBUF = RxdByte; //接收到的数据直接发回,用以提示输入信息是否被正确接收 ... } if (TI) //字节发送完毕 { TI = 0; //手动清零发送中断标志位 } } 完整模板代码 /*********************************************************************** * 中断的4个寄存器(都为8位) * 中断允许 中断优先级 定时器/计数器工作模式 定时器/计数器控制 * IE IP TMOD TCON * 位寻址 固定 不可位寻址 位寻址 * EA|ET1|ES1 ---- T1|T0 TR0|TR1 * 串口控制寄存器 SCON 不可位寻址 置0x50 * 中断优先级(0~5):INT0 T0 INT1 T1 TX/RX T2 * * 具体的可转入reg52.h头文件中查看 ************************************************************************/ #include /******************************定义引脚*********************************/ /******************************定义全局变量*****************************/ /*************************定时器********************************/ unsigned char T0RH = 0; //T0重载值高字节 unsigned char T0RL = 0; //T0重载值低字节 /************************串口通信*******************************/ unsigned char RxdByte = 0; //串口接收到的字节 /****************************函数声明***********************************/ void ConfigTimer0(unsigned int ms); void ConfigUART(unsigned int baud); /*主函数*/ void main() { EA = 1; //使能总中断 ConfigTimer0(1); //配置为1ms ConfigUART(9600); //配置波特率为9600 while(1) { } } /*配置并启动T0,ms-T0定时时间*/ void ConfigTimer0(unsigned int ms) { unsigned long tmp; tmp = 11059200 / 12; //计算所需的计数值(ms换算成s) tmp = (tmp * ms) / 1000; tmp = 65536 - tmp; //计算定时器重载值 //tmp = tmp + 13; //补偿中断响应延时造成的误差 T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节 T0RL = (unsigned char)tmp; TMOD &= 0xF0; //清零T0控制位 TMOD |= 0x01; //配置T0为模式1 TH0 = T0RH; //加载T0重载值 TL0 = T0RL; ET0 = 1; //使能T0中断 TR0 = 1; //启动T0 } /*串口配置函数,baud-通信波特率*/ void ConfigUART(unsigned int baud) { SCON = 0x50; //配置串口为模式1 TMOD &= 0x0F; //清零T1控制位 TMOD |= 0x20; //配置T1为模式2 TH1 = 256 - (11059200/12/32)/baud; //计算T1重载值(32:PCON配置为1,一个数据监测32次,保证准确性) TL1 = TH1; //初始等于重载值 ET1 = 0; //禁止T1中断 ES = 1; //使能串口中断 TR1 = 1; //启动T1 } /******************************自定义函数*******************************/ /******************************自定义函数END****************************/ /*T0中断服务函数*/ void InterruptTimer0() interrupt 1 { TH0 = T0RH; //重载初值 TL0 = T0RL; /**************************定时器0功能实现***************************/ /*******************************END**********************************/ } /*UART中断服务函数*/ void InterruptUART() interrupt 4 { if (RI) //接收到字节 { RI = 0; //手动清零接收中断标志位 RxdByte = SBUF; //接收到的数据(8位)保留在接收字节变量中 SBUF = RxdByte; //接收到的数据直接发回 //用以提示输入信息是否被正确接收 /**************************串口通信功能实现***************************/ /********************************END**********************************/ } if (TI) //字节发送完毕 { TI = 0; //手动清零发送中断标志位 } } 



。
下一篇:51单片机的控制寄存器详解
史海拾趣
|
完整版UCOS-II V2.52源代码,需要的朋友赶快下 这个系统包无需改动,嵌入系统即可使用,主要是方便新伙计少走弯路,内容是原版邵贝贝光盘中的系统代码,放心使用! … 查看全部问答> |
|
一个LED的N种玩法(五)----WatchDog Timer 一个LED的N种玩法(五)--WatchDog Timer Author: chenzhufly Email: chenzhufly@126.com 2010-05-02 一.WatchDog Timer 概述 看门狗的目的是当进入错误状态一定时间后复位微控制器。当看门狗使能时,如果用户没有在一定时间内喂狗(看门狗定时 ...… 查看全部问答> |
|
有一个项目,供电电压是1000V直流的,需要转为5V,功率在2W左右.由于电压较高,如用PWM降压常规的器件耐压达不到,不知大家有没有好的方案,不甚感激!… 查看全部问答> |
|
代码如下: pmeidacontrol->pause() 视频已经暂停了 m_Graphs->pMC->GetState(2000,(OAFilterState*)&pfs); pfs为State_Paused 暂停状态 hr=m_Graphs->pBV->GetCurrentImage(&bitmapSize,NULL); hr的值为E_INVALIDARG 查了好多资料 还是没找到 ...… 查看全部问答> |
|
eboot显示一个 logo, 但进去系统的中间黑屏,我想继续在 oal中显示 logo, 去掉lcd初始化函数调用, 可看 OEMInit 函数,没见 初始化LCD部分代码, OEMInit 上下文周围也没找到 初始LCD有关的函数. 麻烦给个提示,谢谢 平台是 PXA270+WINCE6.0… 查看全部问答> |
|
java 调用DLL 读串口,不久就死了,请帮忙看看什么原因? 经过仔细分析问题出这dll这里,但始终找不到解决办法,请大家帮忙看看,谢谢! dll代码如下: JNIEXPORT jstring JNICALL Java_getGPS (JNIEnv * env, jobject obj) { char * cIpAddress =compressWideChar((LPCWSTR)L\"empty value! ...… 查看全部问答> |
|
关于格式转换函数sprintf(): 我想用sprintf()函数将一个usigned int型变量转换为字符串从串口发送出去 结果调用的时候发现不对 我先定义DeocdeNum=2000;UCHAR *CH 保存转换后的字符串 printf(ch,\"%d\",DeocdeNum); 结果我发现在程序中 Deoc ...… 查看全部问答> |




