80C51系列单片机波特率自动检测的通用程序
- 格式:pdf
- 大小:71.14 KB
- 文档页数:2
#include "reg51.h"#include "KEY.h"#include "SMG.h"#include "Vol_Measure.h"#include "X25045.h"sbit KEY = P1^5;uchar Channel=1; 默认通1uchar SETTING=0; 系统状态标志uchar SET_FLAG=0; 设置状态标志按键功能函数void Key_Func(void){static uchar count=0;char TH=0,TL=0; 山下限switch(key_scan()){case 1 ESC键{SETTING=1; 系统进入设置状态SET_FLAG=SET_TH; 默认设置上限break;}case 2 Enter键{if(SETTING) 进入系统设置状态{count++;switch(count){case 1 SET_FLAG=SET_TL;break; 第一次设置上限case 2 SETTING=0;count=0;break; 第二次退出设置}}break;}case 3{if(SETTING) 进入系统设置{if(SET_FLAG==SET_TH) 上限设置{switch(Channel){case 1{TH=Read_Data(TH1_Address,0);TL=Read_Data(TL1_Address,0);TH-=1; 上限减0.1Vif(THTL) 上限大于下限,则设置新上限Write_Data(TH,TH1_Address,0);break;}case 2{TH=Read_Data(TH2_Address,0);TL=Read_Data(TL2_Address,0);TH-=1; 上限减0.1Vif(THTL) 上限大于下限,则设置新上限Write_Data(TH,TH2_Address,0);break;}case 3{TH=Read_Data(TH3_Address,0);TL=Read_Data(TL3_Address,0);TH-=1; 上限减0.1Vif(THTL) 上限大于下限,则设置新上限Write_Data(TH,TH3_Address,0);break;}case 4{TH=Read_Data(TH4_Address,0);TL=Read_Data(TL4_Address,0);TH-=1; 上限减0.1Vif(THTL) 上限大于下限,则设置新上限Write_Data(TH,TH4_Address,0);break;}}}else if(SET_FLAG==SET_TL) 下限设置{switch(Channel){case 1{TH=Read_Data(TH1_Address,0);TL=Read_Data(TL1_Address,0);TL-=1; 下限减0.1Vif(TL=0) 下限不小于零,则设置新下限Write_Data(TL,TL1_Address,0);break;}case 2{TH=Read_Data(TH2_Address,0);TL=Read_Data(TL2_Address,0);TL-=1; 上限减0.1Vif(TL=0) 下限不小于零,则设置新下限Write_Data(TL,TL2_Address,0);break;}case 3{TH=Read_Data(TH3_Address,0);TL=Read_Data(TL3_Address,0);TL-=1; 下限减0.1Vif(TL=0) 下限不小于零,则设置新下限Write_Data(TL,TL3_Address,0);break;}case 4{TH=Read_Data(TH4_Address,0);TL=Read_Data(TL4_Address,0);TL-=1; 下限减0.1Vif(TL=0) 下限不小于零,则设置新下限Write_Data(TL,TL4_Address,0);break;}}}}else 退出系统设置{Channel--;if(Channel1){Channel=4;}Select_Channel(Channel);}break;}case 4{if(SETTING) 进入系统设置{if(SET_FLAG==SET_TH) 上限设置{switch(Channel){case 1{TH=Read_Data(TH1_Address,0);TL=Read_Data(TL1_Address,0);TH+=1; 上限加0.1Vif(TH=50) 上限不大于5.0V,则设置新上限Write_Data(TH,TH1_Address,0);break;}case 2{TH=Read_Data(TH2_Address,0);TL=Read_Data(TL2_Address,0);TH+=1; 上限加0.1Vif(TH=50) 上限不大于5.0V,则设置新上限Write_Data(TH,TH2_Address,0);break;}case 3{TH=Read_Data(TH3_Address,0);TL=Read_Data(TL3_Address,0);TH+=1; 上限加0.1Vif(TH=50) 上限不大于5.0V,则设置新上限Write_Data(TH,TH3_Address,0);break;}case 4{TH=Read_Data(TH4_Address,0);TL=Read_Data(TL4_Address,0);TH+=1; 上限加0.1Vif(TH=50) 上限不大于5.0V,则设置新上限Write_Data(TH,TH4_Address,0);break;}}}else if(SET_FLAG==SET_TL) 下限设置{switch(Channel){case 1{TH=Read_Data(TH1_Address,0);TL=Read_Data(TL1_Address,0);TL+=1; 下限减0.1Vif(TLTH) 下限小于上限,则设置新下限Write_Data(TL,TL1_Address,0);break;}case 2{TH=Read_Data(TH2_Address,0);TL=Read_Data(TL2_Address,0);TL+=1; 下限减0.1Vif(TLTH) 下限小于上限,则设置新下限Write_Data(TL,TL2_Address,0);break;}case 3{TH=Read_Data(TH3_Address,0);TL=Read_Data(TL3_Address,0);TL+=1; 下限减0.1Vif(TLTH) 下限小于上限,则设置新下限Write_Data(TL,TL3_Address,0);break;}case 4{TH=Read_Data(TH4_Address,0);TL=Read_Data(TL4_Address,0);TL+=1; 下限减0.1Vif(TLTH) 下限小于上限,则设置新下限Write_Data(TL,TL4_Address,0);break;}}}}else 退出系统设置{Channel++;if(Channel4){Channel=1;}Select_Channel(Channel);}break;}defaultbreak;}}uchar key_scan(void){static uchar key_state = 0;static uchar key_input = 0;uchar key_return = 0;uchar key_press = 0;P2=key_input;switch(key_state){case key_state_0 按键初始态。
//实例100:电机转速表设计#include<reg51.h> //包含单片机寄存器的头文件#include<intrins.h> //包含_nop_()函数定义的头文件sbit RS=P2^0; //寄存器选择位,将RS位定义为P2.0引脚sbit RW=P2^1; //读写选择位,将RW位定义为P2.1引脚sbit E=P2^2; //使能信号位,将E位定义为P2.2引脚sbit BF=P0^7; //忙碌标志位,,将BF位定义为P0.7引脚unsigned char code digit[ ]={"0123456789"}; //定义字符数组显示数字unsigned int v; //储存电机转速unsigned char count; //储存定时器T0中断次数bit flag; //计满1秒钟标志位/*****************************************************函数功能:延时1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒***************************************************/void delay1ms(){unsigned char i,j;for(i=0;i<10;i++)for(j=0;j<33;j++);}/*****************************************************函数功能:延时若干毫秒入口参数:n***************************************************/void delay(unsigned char n){unsigned char i;for(i=0;i<n;i++)delay1ms();}/*****************************************************函数功能:判断液晶模块的忙碌状态返回值:result。
微控制器技术复习题-第一章1、计算机中最常用的字符信息编码是()(A) ASCII (B) BCD码 (C) 余3码 (D) 循环码2、单片微型计算机有CPU、存储器和I/O三部分组成。
3、除了单片机这一名称之外,单片机还可称为微控制器和嵌入式控制器。
4、在家用电器中使用单片机应属于微计算机的()(A)辅助设计应用(B)测量、控制应用(C)数值计算应用(D)数据处理应用5、80C51基本型单片机内部程序存储器容量为()。
(A)16K (B)8K (C)4K (D)2K6、 8051与8751的区别是:()(A)内部数据存储单元数目的不同(B)内部数据存储器的类型不同(C)内部程序存储器的类型不同(D)内部的寄存器的数目不同第二章1、所谓CPU是指()A、运算器和控制器B、运算器和存储器C、输入输出设备D、控制器和存储2、MCS-51单片机内部包括哪些主要逻辑功能部件?3、80C51在物理上有4个独立的存储器空间。
4、使用8031芯片时,需将/EA引脚接低电平,因为其片内无程序存储器。
5、若不用MCS-51片内存储器,引脚EA必须接地。
6、80C51单片机的EA信号有什么功能? 在使用80C51时,EA信号引脚应如何处理,程序从何处什么地址开始执行?在使用80C31时, EA信号引脚应如何处理,程序从何处什么地址开始执行?7、8051单片机片内RAM低128个存储单元划分为哪3个主要部分?各部分主要功能是什么?8、MCS-51单片机访问外部存储器时,利用ALE信号锁存来自P0口的低8位地址信号。
9、请说明80C51单片机ALE引脚的时序功能,并举例说明其在系统中有哪些应用?10、8051单片机共有40个引脚,除了4个8位的端口和2根电源共34根之外,还有6根请分别说明它们一种主要的功能。
11、在80C51单片机应用系统中,可以作为时钟输出的是()引脚。
(A)RXD (B)RST (C)ALE (D)XTAL212、通过堆栈操作实现子程序调用,首先就要把PC的内容入栈,以进行断点保护。
《单片机原理及应用》习题库单位:广东松山职业技术学院电气工程系自动化教研室编者:田亚娟等审核:《单片机原理及应用》精品课程项目组适用专业:电气自动化技术等专业一、填空题1.单片机与普通计算机的不同之处在于其将_CPU__、存储器和__I/O_3部分集成于一块芯片之上。
2.CPU主要由运算器和控制器组成。
CPU中的布尔处理器用来处理位操作。
3.MSC-51系列单片机中,片内无ROM的机型是8031 ,有4KB ROM的机型是_8051_,而有4KB EPROM 的机型是8751 。
4.-32的补码为11100000 B,补码11011010B代表的真值为_-38__D。
5.原码数BFH=_-63_D,原码数6EH=_110_D。
6.100的补码=_64_H,-100的补码= 9C H7.在8031单片机内部,其RAM高端128个字节的地址空间称为特殊功能寄存器或SFR 区,但其中仅有_21_个字节有实际意义。
8.通常单片机上电复位时PC=_0000_H,SP=_07_H,通用寄存器则采用第_0_组,这一组寄存器的地址范围是从_00 H~_07_H。
9.若PSW为18H,则选取的是第_3__组通用寄存器。
10.8031单片机复位后R4所对应的存储单元地址为_04_H,因上电时PSW=_00_H。
11.若A中数据为63H,那么PSW的最低位(即奇偶位P)为_0_。
12.在微机系统中,CPU是按照程序计数器PC 来确定程序的执行顺序的。
13.在8031单片机中,使用P2、P0口传送地址信号,且使用了P0口来传送数据信号,这里采用的是总线复用技术。
14.堆栈遵循先进后出(或后进先出)的数据存储原则,针对堆栈的两种操作为_PUSH_和_POP_。
15.当8051地RST端上保持两个机器周期以上低电平时,8051即发生复位。
16.使用8031单片机时需将EA引脚接_低__电平,因为其片内无程序存储器。
17.8位机中的补码数80H和7EH的真值分别为_-128__和_127 。
51 单片机串行通讯中波特率的自动检测本文介绍一种在80C51 串行通讯应用中自动检测波特率的方法。
按照经验,程序起动后所接收到的第1个字符用于测量波特率。
这种方法可以不用设定难于记忆的开关,还可以免去在有关应用中使用多种不同波特率的烦恼。
人们可以设想:一种可靠地实现自动波特检测的方法是可能的,它无须严格限制可被确认的字符。
问题是:在各种的条件下,如何可以在大量允许出现的字符中找出波特率的定时间隔。
显然,最快捷的方法是检测一个单独位时间(single bit time),以确定接收波特率应该是多少。
可是,在RS-232 模式下,许多ASCII 字符并不能测量出一个单独位时间。
对于大多数字符来说,只要波特率存在合理波动(这里的波特率是指标准波特率),从起始位到最后一位“可见”位的数据传输周期就会在一定范围内发生变化。
此外,许多系统采用8 位数据、无奇偶校验的格式传输ASCII 字符。
在这种格式里,普通ASCII 字节不会有MSB 设定,并且,UART总是先发送数据低位(LSB),后发送数据高位(MSB),我们总会看见数据的停止位。
在下面的波特率检测程序中,先等待串行通讯输入管脚的起始信号(下降沿),然后起动定时器T0。
在其后的串行数据的每一个上升沿,将定时器T0的数值捕获并保存。
当定时器T0溢出时,其最后一次捕获的数值即为从串行数据起始位到最后一个上升沿(我们假设是停止位)过程所持续的时间。
CmpTable 表格列出了每一波特率的最大测量时间。
这些数据是经过选择的,所以,4 个数据位时间(加上起始位时间)仍可产生正确的波特率。
使用这种方法时,必须遵守一个假设:这种技术仅取决于所接收到的一个字符,接收这个字符的波特率必须大于最低波特率。
本质上来说,这意味着这个字符必须来自正常敲击键盘时所产生的字符。
在PC上,我们不可能快速、连续地敲击两个字符,以欺骗程序。
但是,PC的功能键具有一个问题,因为它会连续发送两个紧挨着的字符,使程序检测得到错误的波特率。
80C51单片机原理RAM地址寄存器 RAM 128B 程序地址寄存器P0驱动器 P2锁存器 P2驱动器P1锁存器 暂存器2 B 寄存器 4KB ROM暂存器1ACC SP P0锁存器 PC PC 增1 缓冲器 P3锁存器 OSC中断、串行口及定时器PSW ALU DPTRP1驱动器 P3驱动器XTAL1XTAL2 P0.0~P0.7 P2.0~P2.7 P3.0~P3.7 P1.0~P1.7 RST ALEV CCV SS定时控制 指令译码器 指令寄存器 PSEN EA表2-1 P3口各引脚与第二功能表PSW 的各位定义见表80C51 P0~P3接口功能简见大多数口线都有双重功能,介绍如下: 1、P0口具有双重功能:(1) 作为通用I/O ,外接I/O 设备。
(2) 作为地址/数据总线。
在有片外扩展存储器的系统 中,低8位地址和数据由P0口分时传送。
PSW 位地址 PS W.7PSW .6PSW .5 PSW .4 PSW .3 PSW .2 PSW .1 PSW .0 位标志CY ACF0RS1RS0OVF1P2、P1口是唯一的单功能口:作为输入/输出口,P1口的每一位都可作为输入/输出口。
3、P2口具有双重功能:(1)作为输入/输出口。
(2)作为高8位地址总线。
在有片外扩展存储器的系统中,高8位地址由P2口传送。
4、P3口具有双重功能:(1)作第一功能使用时,其功能为输入/输出口。
(2)作第二功能使用时,每一位功能定义如表2.1所示。
80C51单片机的4个I/O口都是8位双向口,这些口在结构和特性上是基本相同的,但又各具特点,以下将分别介绍之。
图2-9 P0口某位的结构图2-10 P1口某位的结构1D CPQQ MUX& T1T2锁存器地址/数据控制信号C V CC内部总线写锁存器读锁存器读引脚P0.X引脚12DCPQQ T锁存器V CC内部总线写锁存器读锁存器读引脚P1.X引脚12图2-11 P2口某位的结构图2-12 P3口某位的结构P0~P3口使用时应注意事项1、如果80C51单片机内部程序存贮器ROM 够用,不需要扩展外部存贮器和I/O接口,80C51的四个口均可作I/O 口使用。
大工11春《单片机原理及应用》在线作业一一、单选题(共10 道试题,共60 分。
)V 1. 80C51单片机内工作寄存器区的地址为()。
A. 00H~1FHB. 20H~2FHC. 30H~7FHD. 00H~7FH2. 若(A)=84H,(30H)=8DH,执行指令ADD A,30H之后()。
A. (CY)=0,(OV)=0B. (CY)=0,(OV)=1C. (CY)=1,(OV)=0D. (CY)=1,(OV)=13. 指令“MOV A,R0”采用的寻址方式是()。
A. 寄存器寻址B. 直接寻址C. 寄存器间接寻址D. 立即寻址4. 80C51单片机复位后,SP为()。
A. 00HB. 07HC. FFHD. 不定5. 以下不属于特殊功能寄存器SFR的是()。
A. 程序计数器PCB. 累加器ACCC. 堆栈指针SPD. 程序状态字寄存器PSW6. 若(A)=C9H,(R2)=54H,(CY)=1,执行指令SUBB A,R2之后()。
A. (CY)=0,(OV)=0B. (CY)=0,(OV)=1C. (CY)=1,(OV)=0D. (CY)=1,(OV)=17. 80C51单片机中,晶振频率为12MHz时机器周期为()。
A. 0.5μsB. 1.0μsC. 1.5μsD. 2.0μs8. 以下关于补码说法错误的是()。
A. 在计算机中,对带符号数的运算均采用补码B. 正数的补码与其原码相同C. 负数的补码与其原码相同D. 负数的补码为其反码末位加19. 若(R0)=30H,(30H)=5AH,指令“MOV A,@R0”执行后,累加器A的内容为()。
A. 00HB. 30HC. 5AHD. 8AH10. 若(R1)=30H,(A)=20H,执行指令MOV @R1,A后,(30H)=()。
A. 10HB. 20HC. 30HD. 50H二、判断题(共10 道试题,共40 分。
)1. 80C51单片机片内RAM的地址空间为64KB。
乙机发送,甲机接收。
请画出电路图并写出初始化发送(查询)和接收(中断方式)程序。
2、口线P1.0接一个发光二极管,由定时器0控制,用于演示1秒钟亮、1秒钟暗的效果。
3、给80C51单片机扩展一片6116,0809和8155,要求0809采用中断方式,8通道工作;采用138译码选择芯片。
请画出系统连接图,写出各芯片的地址范围并写出8155内各口及其内部的RAM地址范围。
4、已知系统的连接如图所示,试编写程序实现下列功能:(1).编写上电显示程序,显示“123456”。
(2).编写主程序,功能为:当有键按下(0~7号)时,都显示键号;无键按下,保持原有显示状态。
5、选用DAC0832芯片产生一个三角波,要求幅值为0~2.5V。
1200bps,甲机发送数据88H(查询方式),乙机接收(中断方式)。
请画出电路图并编程实现上述功能。
7、已知一单片机应用系统如下图所示。
试回答问题并编写显示程序,以1秒为间隔,亮暗相间,显示“88888888”。
(1).写出各口的地址和控制字A口地址:B口地址:C口地址:控制口地址:控制字:(2).显示程序8、已知ADC0809单片机的连接如下图所示,试写出启动0809第3通道A/D转换的程序段。
(1)、把外部2000H内容送到内部RAM的20H单元。
(2)、找出20H~22H三个单元中的最大数,放在A累加器中。
9、编写程序完成以下功能:每响应一次外部中断,发光二极管亮一秒钟。
六、简单编程题:(1)、用间接寻址方式,把外部20H内容送到内部RAM的20H单元。
(2)、依据第四题接线图,写出启动0809第3通道A/D转换的程序段。
(3)、编写串行口方式1串行发送初始化程序。
(省略波特率发生器初始化)。
10、假定甲乙机以方式1进行串行数据通信,晶振=6MHz,要求波特率为1200。
甲机发送,乙机接收。
请画出电路图并计算出波特率,写出初始化发送和接收程序。
11、当系统选用12MHz晶体振荡器时,由定时器0控制产生周期为4ms(脉冲宽度为2ms)的方波序列(采用中断方式),并由P1.0输出,请编写实验程序。
#include <c8051f000.h>#include <intrins.h>//----------------------------------------------------------------------------- #define uchar unsigned char#define uint unsigned int#define BAUDRATE#define SYSCLKvoid SYSCLK_Init (void);void delaynus(unsigned int q) ;void PORT_Init (void);void SPI0_Init (void);void LCD_Init(void);void SendSPIByte(unsigned char ch);void delaynms (unsigned int j);void writecom(unsigned char com);void writedata(unsigned char d);void writechar(unsigned char ua);void Write_COM(uchar ins);void lcden(datad);void LCD_set_xy( unsigned char x, unsigned char y );void LCD_write_string(unsigned char n);void lcd_key1(void);void lcd_key2(void);void lcd_key3(void);void lcd_key4(void);void UART0_Init (void);void presskey(void);//----------------------------------------------------------------------------- // Global CONSTANTS//----------------------------------------------------------------------------- sbit S3=P1^0;sbit S4=P1^1;sbit S5=P1^2;sbit S6=P1^3;sbit lcdcs=P3^0;unsigned char comd,kk,sdf,ppca;unsigned char virt_port,v,b,m;unsigned char lcd_data_count;unsigned char *lcdpoint;unsigned char qqq;unsigned char data8;unsigned int i;//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------void main(void){WDTCN = 0xde; // disable watchdog timerWDTCN = 0xad;SYSCLK_Init ();PORT_Init ();UART0_Init() ; // initialize crossbar and GPIOSPI0_Init ();LCD_Init() ;delaynms (20);delaynus (100);LCD_set_xy(0X00,0);delaynus (200);presskey();delaynus (200);LCD_write_string(16);delaynus (200);while(1){if(S3==0){Write_COM(0X01);delaynms (200);LCD_set_xy(0X00,0);delaynus (200);lcd_key1();delaynus (200);LCD_write_string(6);delaynus (200);}else if(S4==0){Write_COM(0X01);delaynms (200);LCD_set_xy(0X00,0);delaynus (200);lcd_key2();delaynus (200);LCD_write_string(6);delaynus (200);}else if(S5==0){Write_COM(0X01);delaynms (200);LCD_set_xy(0X00,0);delaynus (200);lcd_key3();delaynus (200);LCD_write_string(6);delaynus (200);}else if(S6==0){Write_COM(0X01);delaynms (200);LCD_set_xy(0X00,0);delaynus (200);lcd_key4();delaynus (200);LCD_write_string(6);delaynus (200);}else{}}}//-----------------------------------------------------------------------------// Initialization Subroutines//-----------------------------------------------------------------------------//-----------------------------------------------------------------------------// PORT_Init//-----------------------------------------------------------------------------void PORT_Init (void){XBR0 = 0x27; // XBAR0: Initial Reset ValueXBR1 = 0x00; // XBAR1: Initial Reset ValueXBR2 = 0x5c; // XBAR2: Initial Reset ValuePRT0CF = 0x14; // Output configuration for P0PRT1CF = 0x10; // Output configuration for P3PRT3CF = 0x01; // Output configuration for P3}//-----------------------------------------------------------------------------// SYSCLK_Init//-----------------------------------------------------------------------------void SYSCLK_Init (void){OSCXCN = 0x67; // start external oscillator withfor (i=0; i < 256; i++) ; // XTLVLD blanking interval (>1ms)while (!(OSCXCN & 0x80)) ; // Wait for crystal osc. to settleOSCICN = 0x88; // select external oscillator as SYSCLK }//-----------------------------------------------------------------------------// SPI0_Init//-----------------------------------------------------------------------------void SPI0_Init (void){SPI0CFG = 0x07; // data sampled on 1st SCK rising edge SPI0CFG|=0xC0; //CKPOL =1;SPI0CN = 0x03; // Master mode; SPI enabled; flagsSPI0CKR = SYSCLK/2/2000000-1; // SPI clock <= 8MHz (limited by// EEPROM spec.)}//-----------------------------------------------------------------------------// UART0_Init//-----------------------------------------------------------------------------void UART0_Init (void){SCON = 0x50; // SCON: mode 1, 8-bit UART, enable RX TMOD = 0x20; // TMOD: timer 1, mode 2, 8-bit reload TH1 = -(SYSCLK/BAUDRATE/16); // set Timer1 reload value for baudrate TR1 = 1; // start Timer1CKCON |= 0x10; // Timer1 uses SYSCLK as time basePCON |= 0x80; // SMOD = 1TI = 1; // Indicate TX ready}//-----------------------------------------------------------------------------// LCD_Init//-----------------------------------------------------------------------------void LCD_Init(void) //向LCD送命令{// unsigned int xdata x;delaynms(100);datad=0x00;SendSPIByte(datad);delaynms(10);Write_COM(0x30);delaynms(10);Write_COM(0x30);delaynms(10);Write_COM(0x30);delaynms(10) ;Write_COM(0x28);delaynms(100);virt_port=0;SendSPIByte(virt_port);lcden(virt_port);Write_COM(0x01);delaynms(100);Write_COM(0x06);delaynms(10) ;Write_COM(0x0C);delaynms(500) ;}//----------------------------------------------------------------------------- // SendSPIByte//----------------------------------------------------------------------------- void SendSPIByte(unsigned char ch){ lcdcs=1;delaynus(100);SPIF = 0;SPI0DAT = ch;while (SPIF == 0);delaynus(100);lcdcs=0;delaynus(100);_nop_(); // 等待写结束}//----------------------------------------------------------------------------- // lcden//----------------------------------------------------------------------------- void lcden(datad){datad|=0x08;SendSPIByte(datad);datad&=0xf7;SendSPIByte(datad);}//----------------------------------------------------------------------------- // delaynms//----------------------------------------------------------------------------- void delaynms (unsigned int uu){unsigned int oo,ll;for (oo=0;oo<uu;oo++){for(ll=0;ll<1140;ll++);}}//----------------------------------------------------------------------------- // writechar//----------------------------------------------------------------------------- void writechar(unsigned char ua){uint j;uchar t,x;for(j=0;j<500;j++);datad|=0x02;SendSPIByte(datad);datad|=ua&0xf0;SendSPIByte(datad);datad|=0x08;SendSPIByte(datad);for(x=0;x<3;x++);datad&=0xf7;SendSPIByte(datad);for(x=0;x<3;x++);datad&=0x07;delaynus(100);SendSPIByte(virt_port);t|=ua&0x0f;datad|=t<<4;SendSPIByte(datad);for(x=0;x<3;x++);datad|=0x08;SendSPIByte(datad);for(x=0;x<3;x++);datad&=0xf7;SendSPIByte(datad);for(x=0;x<3;x++);datad=0x00;t=0x00;SendSPIByte(datad);}//----------------------------------------------------------------------------- // Write_COM//----------------------------------------------------------------------------- void Write_COM(uchar ins){uchar t;uint j;for(j=0;j<5000;j++); //用延时代替查询virt_port|=ins&0xf0;SendSPIByte(virt_port);//LCDE=1;virt_port|=0x08;SendSPIByte(virt_port);for(i=3;i>0;i--);virt_port&=~0x08;SendSPIByte(virt_port);virt_port&=0x07;SendSPIByte(virt_port);t=ins<<4;virt_port|=t&0xf0;SendSPIByte(virt_port);virt_port|=0x08;SendSPIByte(virt_port);for(i=3;i>0;i--);virt_port&=~0x08;SendSPIByte(virt_port);virt_port=0;SendSPIByte(virt_port);}//-----------------------------------------------------------------------------// LCD_set_xy//-----------------------------------------------------------------------------void LCD_set_xy( unsigned char x, unsigned char y ){unsigned char address;if (y == 0) address = 0x80 + x;elseaddress = 0xc0 + x;Write_COM(address);}//-----------------------------------------------------------------------------// LCD_write_string//-----------------------------------------------------------------------------void LCD_write_string(unsigned char n){unsigned char data1;for(n;n>0;n--){data1=*lcdpoint;writechar(data1);delaynms(100);lcdpoint++;delaynus(10);}}//-----------------------------------------------------------------------------// presskey//-----------------------------------------------------------------------------void presskey(void){unsigned char xdata DDCdata[16]={0x50,0x4c,0x45,0x41,0x53,0x45,0x20,0x50,0x52,0x45,0x53,0x53,0x20,0x4b,0x4 5,0x59};lcdpoint=&DDCdata;}//-----------------------------------------------------------------------------// lcd_key1//-----------------------------------------------------------------------------void lcd_key1(void){unsigned char xdata key1ok[6]={0x53,0x33,0x20,0x4f,0x4b,0x21};lcdpoint=&key1ok;}//-----------------------------------------------------------------------------// lcd_key2//-----------------------------------------------------------------------------void lcd_key2(void){unsigned char xdata key2ok[6]={0x53,0x34,0x20,0x4f,0x4b,0x21};lcdpoint=&key2ok;}//-----------------------------------------------------------------------------// lcd_key3//-----------------------------------------------------------------------------void lcd_key3(void){unsigned char xdata key3ok[6]={0x53,0x35,0x20,0x4f,0x4b,0x21};lcdpoint=&key3ok;}//-----------------------------------------------------------------------------// lcd_key4//-----------------------------------------------------------------------------void lcd_key4(void){unsigned char xdata key4ok[6]={0x53,0x36,0x20,0x4f,0x4b,0x21};lcdpoint=&key4ok;}//-----------------------------------------------------------------------------// delaynus//-----------------------------------------------------------------------------void delaynus(unsigned int q) //N us延时函数{for (i=0;i<q;i++){_nop_();}}本程序已经完全调试通过,欢迎参考。
自动检测80C51串行通讯的波特率软件设计摘要本文以MCS-51单片机为例,详细介绍了PC机与单片机之间自动检测80C51串行通讯的波特率。
在Windows98下利用串口精灵的串行通讯控件来实现自动检测波特率的功能。
其传送速率(波特率)的发送和接收即是串行口程序启动后所接收到的第1个字符。
其优点是:使用简单方便。
PC机与单片机通过RS-232C 数据总线连接,再通过MAX232电平转换器,两者间不会因为电平的不同而造成数据传输的失误,抗干扰能力强。
本设计主要是通过单片机串行口进行自动检测到的波特率。
这种自动检测的方法以后运用到工业控制中,可以方便工作人员在波特率的检测中,不要再设置固定的波特率了。
这种方法其软件功能完善,控制系统可靠,性价比较高等特点,具有一定的使用和参考价值。
关键字MSC-51(单片机),自动检测,串行通讯,波特率Software Designing of The Baud Rate That The Automatical Examine s for The String Communication of80C51AbstractThis text takes one-chip computer MCS-51 for example, and introduced the Baud Rate of the automatical examines for the string communication between PC and one-chip computer in detail. Under the Windows98, we make use of string the communication control of spirit to carry out the auto examination especially the function of the Baud Rate. The sending out and receiving of its delivering velocity (Baud Rate) is the first string whichis received after the serial programme is started .Its advantage is that the usage is simple and convenience. PC and one-chip computer are connected through the data total line of RS-232C, then pass the electricity conversion machine of MAX232. It will not result in the error that the wrong data delivering because of the different electric. And its anti- interference ability is strong.The origin designs is mainly through One-chip computer string to carry onAutomatically examine especially the Baud Rate. The method of this kind of automatic examination is made use of in the industry control in future. With its usage staff may examination the Baud Rate conveniently. And in is not necessary to establish the fixed Baud Rate again. Its software function of this kind of way is perfect, the control system is dependable, and the rate of price is higher etc .So the system has certain consulting value.KeywordsMSC-51(One-chip computer),Automatic examination,Serial communication,Baud Rate目录第一章单片机简介 (6)1.1 单片机发展历史 (6)1.2 单片机发展趋势 (7)1.3 MCS-51 单片机的引脚功能 (8)第二章系统分析 (12)2.1 系统功能概述 (12)2.2 系统要求及主要内容 (12)2.3 系统技术指标 (13)第三章硬件设计 (13)3.1 硬件设计思想 (13)3.2 器件介绍 (14)第四章软件设计 (17)4.1 串行口通讯技术介绍 (17)4.2 软件设计思想 (29)4.3 单片机通信程序设计 (29)4.4 PC机通信介绍 (32)第五章系统调试 (34)5.1 硬件调试 (34)5.2 软件调试 (34)5.3 综合调试 (37)5.4 故障分析与解决方案 (37)5.5 结论 (38)第六章结束语 (38)参考文献 (39)致谢 (40)附录 (41)附录1 程序清单 (41)附录2 英文资料 (43)附录3 中文资料 (49)自动检测80C51串行通讯的波特率软件设计序言单片机的英文名称是Micro Controller unit,缩写为MCU,又称为微控制器,它是一种面向控制的大规模集成电路芯片。
综合作业1. (单选题) 80C51单片机中,输入/输出引脚中用于专门的第二功能的引脚是( )。
(本题3.0分)A、P0B、P1C、P2D、P3学生答案:未答题标准答案:D解析:得分: 02. (单选题) 80C51单片机的复位信号是( )有效。
(本题3.0分)A、脉冲B、低电平C、高电平D、下降沿学生答案:未答题标准答案:C解析:得分: 03. (单选题) 在中断允许寄存器中,中断控制寄存器EA位的作用是( )。
(本题3.0分)A、CPU总中断允许控制位B、中断请求总标志位C、各中断源允许控制位D、串行口中断允许位学生答案:未答题标准答案:A解析:得分: 04. (单选题) 80C51单片机串行口用工作方式0时( )。
(本题3.0分)A、数据从RDX串行输入,从TXD串行输出B、数据从RDX串行输出,从TXD串行输入C、数据从RDX串行输入或输出,同步信号从TXD输出D、数据从TXD串行输入或输出,同步信号从RXD输出学生答案:未答题标准答案:C解析:得分: 05. (单选题) 80C51的地址总线由( )构成。
(本题3.0分)A、P0和P1B、P0C、P0和P2D、P2学生答案:未答题标准答案:C解析:得分: 06. (单选题) 使用宏来访问绝对地址时,需包含的库文件是( )。
(本题3.0分)A、reg51.hB、startup.hC、intrins.hD、absacc.h学生答案:未答题标准答案:D解析:得分: 07. (单选题) 要使无符号字符型变量a中的数高4位为0,低4位不变,则执行以下哪条语句?( )(本题3.0分)A、a = a & 0x0F;B、a = a & 0xF0;C、a = a | 0x0F;D、a = a | 0xF0;学生答案:未答题标准答案:A解析:得分: 08. (单选题) 单片机CPU不能自动清除中断标志的中断为( )(本题3.0分)A、串口发送中断B、定时器T0溢出中断C、定时器T1溢出中断D、下降沿触发的外部中断0学生答案:未答题标准答案:A解析:得分: 09. (单选题) 当定时器T1向单片机的CPU发出中断请求时,若CPU 允许并接受中断请求时,程序计数器PC的内容将被自动修改为( )。
控制软件(2)复习内容1.程序状态字:CY: 进位标志。
有进位/借位时置1AC:半进位标志。
D3->D4进位/借位时置1OV:溢出标志。
带符号数超出-128~127置1,乘法结果超过255,除数为0P:奇偶标志。
A中的1的个数为奇数F0:用户设置标志RS1,RS0: 通用寄存器选择位2.振荡周期:1/fOSC时钟周期:2/fOSC机器周期:12/fOSC=T3. 并行I/O(P0~P3)准双向:输入时先向口线写“1”只有P1口没有第二功能,P0口的第二功能:第8位地址和数据总线复用P2口的第二功能:高8位地址4.并行口的负载能力P0口的每一位口线可以驱动8个LSTTL负载。
在作为通用 I/O口时,由于输出驱动电路是开漏方式,由集电极开路(OC门)电路或漏极开路电路驱动时需外接上拉电阻P1、P2、P3口的每一位能驱动4个LSTTL负载。
它们的输出驱动电路设有内部上拉电阻,所以可以方便地由集电极开路(OC门)电路或漏极开路电路所驱动,而无须外接上拉电阻。
5.单片机控制信号引脚的时钟脉冲。
ALE:地址锁存信号输出端,输出频率为6/foscRST:复位引脚,复位脉冲宽度要大于2个机器周期。
EA:外接程序存储器,此引脚接地,否则接高电平。
PSEN:片外程序存储器读选通,低电平有效6.低功耗操作方式①节电方式将PCON中的IDL(PCON.0)置位,就进入节电方式。
此时,提供给CPU的时钟信号被切断,但时钟信号仍提供给RAM、定时器、中断系统合串行口,同时CPU的状态被保留起来。
功耗为:5V*3.7mA=18.5mW。
退出节电方式的方法:①任何一种中断被激活;②硬件复位。
②掉电方式将PCON中的PD(PCON.1),就进入掉电方式。
此时,片内振荡器停止工作,时钟冻结,一切工作都停止只有片内RAM的内容被保持,SFR内容也被破坏。
功耗为2V*0.05mA=0.1mW。
退出掉电方式的方法:硬件复位。
7.数据类型及存储类型只有bit和unsigned char两种数据类型可以直接支持机器指令,必须慎重变量和数据类型的选择。
摘要高速发展的计算机业需要新型人才,需要具有创新的技术、专业的知识和富有团队作业能力的人才,踏着豪迈的脚步我们随着时间走进了21世纪,21世纪科学技术的飞快发展,人们不但在学习,工作方面有了更高的追求。
他们已经不再局限于仅能做到,而是追求着更高的质更高飞跃和省时,省事,低成本成本的快捷方式。
在当今社会,各种智能化控制系统均离不开数据信息的传输。
其中波特率自动检测应用技术在单片机应用中占有很重要的一部分。
通过学习单片机技术,解决实际生活中波特率自动检测的一种方案,性能,特点等,从而应用到实际当中去.通过对单片机的学习,开发出一个完整的系统.包括硬件设计,制作,独立运行及调试的软件及编程。
关键词:波特率检测目录摘要 (1)1. 前言 (3)1.1课题简介 (3)1.2单片机的生产与发展 (4)1.3单片机的特点及应用 (5)1.4AT89S51系列单片机介绍 (6)1.4.1 基本特性 (6)3. 总体设计电路图及工作原理 (7)2.1机型及器件的选择 (7)2.2软、硬件功能划分 (7)3. 系统硬件设计 (8)3.1系统硬件电路设计 (8)3.2硬件设计电路原理图 (9)3.3各元件说明 (9)3.3.1 AT89S51芯片 (9)3.3.2 MAX232CPE芯片 (10)4. 系统软件设计 (13)4.1编程思路 (13)4.1.1 详细设计 (15)4.1.2 编写程序 (15)4.2七段数码显示电路 (16)4.2.1 接口及写入电路 (16)总结 (17)致谢....................................................... 错误!未定义书签。
参考文献. (18)附录1 (19)附录2 (20)利用单片机实现波特率自检测1. 前言1.1 课题简介此课题的设计的目的和意义是以实用性的产品为设计对象,通过完整的设计和制作过程,使我们进一步清楚了解波特率自检测设计制作的流程和特点。
80c51单片机简易计算器源程序#include#include#include#define uint unsigned int#define unch unsigned char#define D8279 XBYTE[0x7EFF]#define CTRL8279 XBYTE[0x7FFF]unchZXM[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};unch n;unch result_flag;unch p;//浮点型数字的精确度unch Q;//小数点前一位数的字形码unch m;//存放键码unch key;//记录按下键盘后所代表的数字或运算符unch temp;//中间变量unch num;//实时记录数字和运算符在内的所有ASC码字符的个数unch num1;//实时记录数字的个数uint a[10]={0};//用于存放运算符两侧数的各个位unch i;//上面数组的循环控制变量unch aa;//小数运算时,记录小数点前面的个数unch bb;//记录小数点后面的变量long total_1,total_2;//total_1表示运算符左边的数,total_2表示运算符右边的数unch operator_flag;//要进行何种运算的标志变量float total_operation,total;//total_operation除法运算时用于存放结果的变量,total表示经过运算后的数float total1_point; //小数运算时用于记录运算符左边的小数float total2_point; //小数运算时用于记录运算符右边的小数unch point_flag;//小数运算的标志变量void Operation();void clear_array()//数组清除函数,用于清除运算符左边或右边的运算数的各个位{for(i=0;i<10;i++)a[i]=0;i=0;}void newset() //8279初始化//{CTRL8279=0x90; //写显示RAM,地址自动加一//CTRL8279=0x34; //定标//CTRL8279=0x10; //8个字符显示右边输入,编码扫描,键盘锁定//}void clear_ram()//总清除命令//{CTRL8279=0xd1;i=CTRL8279;i&=0x80; //读出8279的状态寄存器中显示的状态,重点读DU 位//while(i==0x80) //等待清除完成,直到DU位变成0,说明清除完毕,才可在写显示里写入字形码//{i=CTRL8279;i&=0x80;}}void key_scan() //独立键盘函数归零函数{clear_ram();newset();num=0; //记录数字个数的变量清0num1=0; //记录数字和符号个数的变量清0total_1=0; //运算符左边数暂存变量清0total_2=0;total1_point=0;total2_point=0;//运算符右边数暂存变量清0total=0; //运算结果暂存变量清0clear_array(); //数组清0D8279=0xbf;}void calculate_1() //求得运算符左边的那个数{unch j;long middle;for(j=0,middle=1;j<="">//这里多乘了10倍因为后面会先除以10在作乘法运算for(j=0;j<num1;j++)< bdsfid="137" p=""></num1;j++)<> {middle=middle/10; //每次乘数都要缩小10倍total_1=total_1+a[j]*middle; //将运算符左边的每个数字乘以相应的倍数再累加得到运算符左边的数并存放到total_1中}if(point_flag==1)//出现小数时,则计算得到其值{for(j=0,middle=1;j<bb;j++)< bdsfid="145"p=""></bb;j++)<>middle=middle*10;total1_point=1.0*total_1/middle;//totall_point为整数部分}num1=0; //确定完运算符左边的数后将统计数字个数的变量清0 }void calculate_2() //求得运算符右边的那个数{unch j;long middle;for(j=0,middle=1;j<="" p="">middle=middle*10; //确定最一开始每个数字要乘以的倍数//这里多乘了10倍因为后面会先除以10在作乘法运算for(j=0;j<num1;j++)< bdsfid="159" p=""></num1;j++)<> {middle=middle/10;//每次乘数都要缩小10倍total_2+=a[j]*middle;//将运算符左边的每个数字乘以相应的倍数//再累加得到运算符左边的那个数//并存放到total_2中}if(point_flag==1)//出现小数时则计算得到其值{for(j=0,middle=1;j<bb;j++)< bdsfid="169" p=""></bb;j++)<>middle=middle*10;total2_point=1.0*total_2/middle;}num1=0;//确定完运算符右边的数后将统计数字个数的变量清0 }////////******************用于显示经过运算后得到的整形结果的函数*******************************////////void display(long total_temp){unch j;long middle,temp;n=(long)(log10(total_temp))+1;//确定是几位数for(j=0,middle=1;j<="">middle=middle*10;//middle运算后为100000for(j=0;j<n-1;j++)< bdsfid="185" p=""></n-1;j++)<>{middle=middle/10;//middle每次缩小10倍,例如此处为10000temp=(long)(total_temp/middle);//将结果12345除以10000得到商1D8279=ZXM[temp];total_temp=total_temp-temp*middle; //12345-10000=2345,继续类似确定出每1位,}D8279=ZXM[total_temp]|0x80;}//////*************************用于显示经过运算后得到的浮点型结果的函数***********************/////////void display_decimals(float temp1,unch r){unch j,z[]={0};for(j=0;j<="">{z[j]=(long)(temp1*10);temp1=temp1*10-((long)(temp1*10));// 3.42-3=0.42}while(z[r-1]==0)r--; //如果最后一位是0,继续检测前面一位,直到检测非零值;for(j=0;j<r;j++)< bdsfid="208" p=""></r;j++)<>D8279=ZXM[z[j]];}int1( ) interrupt 2 //计算器矩阵键盘扫描中断函数,从左到右,从上到下{if(num==0) //若输入为第一个数字时,将显示器'0.'{newset();}CTRL8279=0x40; //发送读FIFO/RAM命令//m=D8279;switch(m){case 0x1d: key=7;a[i++]=7; //每按下一个数字就把该数字存入数组中,同时数组控制变量+1num++;num1++; //每按下一个数字,统计数字个数变量+1,统计数字和运算符个数变量+1D8279=0x07;break;case 0x1c: key=8;a[i++]=8;num++;num1++;D8279=0x7f;break;case 0x1b: key=9;a[i++]=9;num++;num1++;D8279=0x6f;break;case 0x1a: key='+';operator_flag=4;//运算符标志变量赋予不同值表示不同的运算方式bb=num1-aa; //确定小数点后有几位数calculate_1();//按下一个运算符后就把其左侧的运算数计算出来clear_array();//确定1个运算数后数组清0aa=0;bb=0;point_flag=0;num++; //统计数字和运算符个数变量+1clear_ram();newset();break;case 0x19: key='%';operator_flag=9;bb=num1-aa; //确定小数点后有几位数calculate_1();//按下一个运算符后就把其左侧的运算数计算出来clear_array();//确定1个运算数后数组清0aa=0;bb=0;point_flag=0;num++; //统计数字和运算符个数变量+1clear_ram();newset();bb=num1-aa; //确定小数点后有几位数clear_ram();Operation();result_flag=1;break;case 0x18: key='c';key_scan();break;case 0x15: key=4;a[i++]=4;//每按下一个数字就把该数字存入数组中,同时数组控制变量+1num++;num1++; //每按下一个数字,统计数字个数变量+1,统计数字和运算符个数变量+1D8279=0x66;break;case 0x14: key=5;a[i++]=5;num++;num1++;D8279=0x6d;break;case 0x13: key=6;a[i++]=6;num++;num1++;D8279=0x7d;break;case 0x12: key='-';operator_flag=3;//运算符标志变量赋予不同值表示不同的运算方式bb=num1-aa; //确定小数点后有几位数calculate_1();//按下一个运算符后就把其左侧的运算数计算出来clear_array();//确定1个运算数后数组清0aa=0;bb=0;point_flag=0;num++; //统计数字和运算符个数变量+1clear_ram();newset();break;case 0x11: key='z';operator_flag=8;//运算符标志变量赋予不同值表示不同的运算方式bb=num1-aa; //确定小数点后有几位数calculate_1();//按下一个运算符后就把其左侧的运算数计算出来clear_array();//确定1个运算数后数组清0aa=0;bb=0;point_flag=0;num++; //统计数字和运算符个数变量+1clear_ram();newset();break;case 0x10: key='^';operator_flag=5;bb=num1-aa; //确定小数点后有几位数calculate_1();//按下一个运算符后就把其左侧的运算数计算出来clear_array();//确定1个运算数后数组清0aa=0;bb=0;point_flag=0;num++; //统计数字和运算符个数变量+1clear_ram();newset();bb=num1-aa; //确定小数点后有几位数clear_ram();Operation();result_flag=1;break;case 0x0d: key=1;a[i++]=1;//每按下一个数字就把该数字存入数组中,同时数组控制变量+1num++;num1++;//每按下一个数字,统计数字个数变量+1,统计数字和运算符个数变量+1D8279=0x06;break;case 0x0c: key=2;a[i++]=2;num++;num1++;D8279=0x5b;break;case 0x0b: key=3;a[i++]=3;num++;num1++;D8279=0x4f;break;case 0x0a: key='*';operator_flag=2;//运算符标志变量赋予不同值表示不同的运算方式bb=num1-aa; //确定小数点后有几位数calculate_1();//按下一个运算符后就把其左侧的运算数计算出来clear_array();//确定1个运算数后数组清0aa=0;bb=0;point_flag=0;num++; //统计数字和运算符个数变量+1clear_ram();newset();break;case 0x09: key='!';operator_flag=10;bb=num1-aa; //确定小数点后有几位数calculate_1();//按下一个运算符后就把其左侧的运算数计算出来clear_array();//确定1个运算数后数组清0aa=0;bb=0;point_flag=0;num++; //统计数字和运算符个数变量+1clear_ram();newset();bb=num1-aa; //确定小数点后有几位数clear_ram();Operation();result_flag=1;break;case 0x08: key='k';operator_flag=6;bb=num1-aa; //确定小数点后有几位数calculate_1();//按下一个运算符后就把其左侧的运算数计算出来clear_array();//确定1个运算数后数组清0aa=0;bb=0;point_flag=0;num++; //统计数字和运算符个数变量+1clear_ram();newset();break;case 0x05: key=0;a[i++]=0;//每按下一个数字就把该数字存入数组中,同时数组控制变量+1num++;num1++;//每按下一个数字,统计数字个数变量+1,统计数字和运算符个数变量+1D8279=0x3f;break;case 0x04 :key=',';//相当于输入为0的程序重复执行a[i++]=0;num++;num1++;D8279=0x3f;a[i++]=0;num++;num1++;D8279=0x3f;break;case 0x03: key='.';num++;aa=num1;//确定小数点前有几位数CTRL8279=0x60+aa-1;Q=D8279;CTRL8279=0x80+aa-1;D8279=Q|0x80;point_flag=1;CTRL8279=0x90+aa;break;case 0x02: key='/';operator_flag=1; //运算符标志变量赋予不同值表示不同的运算方式bb=num1-aa; //确定小数点后有几位数calculate_1(); //按下一个运算符后就把其左侧的运算数计算出来clear_array(); //确定一个运算数后数组清0aa=0;bb=0;point_flag=0;num++; //统计数字和运算符个数变量+1clear_ram();newset();break;case 0x01: key='x';operator_flag=7;bb=num1-aa; //确定小数点后有几位数calculate_1();//按下一个运算符后就把其左侧的运算数计算出来clear_array();//确定1个运算数后数组清0aa=0;bb=0;point_flag=0;num++; //统计数字和运算符个数变量+1clear_ram();newset();bb=num1-aa; //确定小数点后有几位数clear_ram();Operation();result_flag=1;break;case 0x00: key='=';bb=num1-aa; //确定小数点后有几位数clear_ram();Operation();result_flag=1;break;}}float en(float y,unch c){unch i;float sum=y;if(c==0)return 1;for(i=0;i<c-1;i++)< bdsfid="432" p=""></c-1;i++)<> sum*=y;return sum;}long jiecheng(unsigned int c){unsigned long sum;sum=1;while(c!=0){sum=sum*c;c--;}return sum;}void jieguo(float total_operation){unch v,w;if((total_operation-(long)total_operation)==0.0){if((long)total_operation!=0)display(total_operation);elseD8279=0xbf;}else{if((long)total_operation!=0){display((long)total_operation);v=(long)log10((long)total_operation)+1;w=8-v;display_decimals(1.0*(total_operation-(long)total_operation),w);}else{D8279=0Xbf;w=7;display_decimals(total_operation,w);}}}//////////**********************显示结果函数*************************////////// void Operation(){ newset();calculate_2();if(total1_point==0)total1_point=1.0*total_1;if(total2_point==0)total2_point=1.0*total_2;if(operator_flag==1)//*************如果输入/运算符**************// {operator_flag=0;//按了=键后计算得到运算符右边的数total=total1_point/total2_point;//转为浮点型数据jieguo(total);}if(operator_flag==2)//*******如果输入*运算符*********//{operator_flag=0;total=total1_point*total2_point;//转为浮点型数据jieguo(total);}if(operator_flag==3)//*******如果输入-运算符***********//{operator_flag=0;total=total1_point-total2_point; //进行减法运算if(total<0) //如果为负数{D8279=0x40;total=total2_point-total1_point;}jieguo(total);}if(operator_flag==4)//********如果输入+运算符*********// { operator_flag=0;total=(total1_point+total2_point);//转为浮点型数据jieguo(total);}if(operator_flag==5)//********如果输入^运算符*********// { operator_flag=0;total=(total1_point*total1_point);//转为浮点型数据jieguo(total);}if(operator_flag==6)//********如果输入√运算符*********// { operator_flag=0;total=log10((long)(total2_point));//转为浮点型数据jieguo(total);}if(operator_flag==7)//********如果输入1/x运算符*********// { operator_flag=0;total=1/(total1_point);//转为浮点型数据jieguo(total);}if(operator_flag==8)//********如果输入ncf运算符*********// { operator_flag=0;total=en(total1_point,(int)total2_point);//转为浮点型数据jieguo(total);}if(operator_flag==9)//**********如果输入%*********//{operator_flag=0;total=(total1_point)/100;//转为浮点型数据jieguo(total);}if(operator_flag==10)//**********如果输入阶乘!*********// { operator_flag=0;total=jiecheng((int)total1_point);jieguo(total);}}void main(){clear_ram(); //总清除newset(); //8279初始化key_scan();IT1=0; //设置INT1中断方式为低电平EX1=1; //允许INT1中断EA=1; //CPU允许中断while(1); //等待中断//}。
自动检测80C51串行通讯中的波特率本文介绍一种在80C51串行通讯应用中自动检测波特率的方法。
按照经验,程序起动后所接收到的第1个字符用于测量波特率。
这种方法可以不用设定难于记忆的开关,还可以免去在有关应用中使用多种不同波特率的烦恼。
人们可以设想:一种可靠地实现自动波特检测的方法是可能的,它无须严格限制可被确认的字符。
问题是:在各种的条件下,如何可以在大量允许出现的字符中找出波特率的定时间隔。
显然,最快捷的方法是检测一个单独位时间(single bit time ),以确定接收波特率应该是多少。
可是,在RS-232模式下,许多ASCII 字符并不能测量出一个单独位时间。
对于大多数字符来说,只要波特率存在合理波动(这里的波特率是指标准波特率),从起始位到最后一位“可见”位的数据传输周期就会在一定范围内发生变化。
此外,许多系统采用8位数据、无奇偶校验的格式传输ASCII 字符。
在这种格式里,普通ASCII 字节不会有MSB 设定,并且,UART 总是先发送数据低位(LSB ),后发送数据高位(MSB ),我们总会看见数据的停止位。
在下面的波特率检测程序中,先等待串行通讯输入管脚的起始信号(下降沿),然后起动定时器T0。
在其后的串行数据的每一个上升沿,将定时器T0的数值捕获并保存。
当定时器T0溢出时,其最后一次捕获的数值即为从串行数据起始位到最后一个上升沿(我们假设是停止位)过程所持续的时间。
CmpTable 表格列出了每一波特率的最大测量时间。
这些数据是经过选择的,所以,4个数据位时间(加上起始位时间)仍可产生正确的波特率。
使用这种方法时,必须遵守一个假设:这种技术仅取决于所接收到的一个字符,接收这个字符的波特率必须大于最低波特率。
本质上来说,这意味着这个字符必须来自正常敲击键盘时所产生的字符。
在PC 上,我们不可能快速、连续地敲击两个字符,以欺骗程序。
但是,PC 的功能键具有一个问题,因为它会连续发送两个紧挨着的字符,使程序检测得到错误的波特率。
80C51系列单片机波特率自动检测的通用程序 An Automatic B aud R ate Detection Pro gram for the80C51Single2Chip Computer
●万新恒龚建明
Wan Xinheng
G ong Jianming
1 引言
在串行异步通讯中,常常希望从机端的波特率能随主机端的不同设置进行自动调整,这在分布式多种波特率通讯系统中可省去波特率硬件设置开关切换的不便。
软件实现波特率自动检测的设计思想常见的有以下两种:一种是当主机启动通讯程序以后,逐一选择波特率向从机发某一固定调试字符(如ASCII1),不断地重复接收和检验过程直至无误。
二是利用串行异步设计标准中文件导引区和记录字符中停止位的逻辑“1”信号,采用软件定时的方法确定出解调参数,然后,以该参数为基准,与随后采样的数据位信号中的周期值相比较以判别出数据位信号中的逻辑“1”或“0”,并将其还原成二进制数以完成整个调解进程[1]。
本文介绍另一种简单可靠的软件实现波特率自动检测的方法,并给出了程序清单及详尽的注解。
该软件方法提高了波特率解调的简捷性和兼容性。
2 编程方法
通讯开始时,从串行口RXD输入一个引导字符(如ASCII a)作为测试字符,当检测到起始位(下降沿)时启动计数器T0,在随后串行数据的每一个上升沿,“捕获”计数器的值并保存,当计数器溢出时,最后的“捕获”值则表示串行接收字符从起始位到停止位的持续计数值。
然后,将此计数值与波特率索引表中每种标准波特率所对应的数据相比较,从而检测出正确的波特率。
对每一种波特率,通过下式计算出所对应的最大计数器预置值,存入表格BdTab中:
最大定时器预置值=
晶振频率(MHz)
波特率
×
5
12以82N21通讯(8位数据位,无奇偶校检, 1位停止位)为例,上式推导如下:
最大定时器预置值=
最小识别时间
机器周期
最小识别时间=
识别位数×字节时间
9
机器周期=12/晶振频率
字节时间=9/波特率
3 程序清单
通用程序清单及详尽的注解如下:;预定义RX BIT P3.0;串行数据接收端
CharH DATA30h;保存TH0值
CharL DATA31h;保存TL0值
BdRt DATA32h;保存波特率最终检测值Display EQU P1;显示调试结果
;复位及中断向量
万新恒,现在华中理工大学固体电子学系工作。
地址:武汉武昌喻家山 邮政编码:430074收稿日期:1997年3月6日(磁盘来稿)
ORG8000h
Begin:ACALL AutoBaud;检测波特率值
MOV Display,BdRt;送波特率索引值
S J MP Begin
;波特率检测子程序
;返回ACC=波特率索引指针
AutoBaud:MOV TMOD,#01h;置T0工作方式1 MOV TH0,#0;初值写入T0
MOV TL0,#0
MOV TCON,#0
MOV CharH,#0;初始化寄存单元
MOV CharL,#0
CHK0: JB RX,CHK0;等待字符起始位
SETB TR0;启动T0
CHK1: JB TF0,CHK3;T0溢出否?
J NB RX,CHK1;检测串行数据上升沿MOV CharH,TH0;“捕获”在上升沿的T0值
MOV CharL,TL0
CHK2: JB TF0,CHK3;T0溢出否?
JB RX,CHK2;检测串行数据下降沿
S J MP CHK1;重复采样
CHK3: CL R TR0;T0溢出处理
CL R TF0;清标志,停止计数
MOV BdRt,#19;建立索引表指针Loop: MOV A,BdRt
MOV DPTR,#BdTab
MOVC A,@A+DPTR;查表比较
DEC BdRt
C J NE A,CharH,Cmp1;检查结果范围
S J MP CmpLow;高字节相等,检查低字
节
Cmp1: J C Match;若表中值<计数值,匹配
DJ NZ BdRt,Loop;表比较完否?
S J MP Match
CmpLow:MOV A,BdRt
MOVC A,@A+DPTR;查表比较
C J NE A,CharL,Cmp2;检查数据范围
SETB C;若相等,则匹配
Cmp2: J C Match;若A<结果低字节,置C
DJ NZ BdRt,Loop;表比较完否?
Match:MOV A,BdRt;比较完
CL R C;取最终波特率索引值
RRC A
MOV BdRt,A;保存
RET
;索引表保存标准波特率所对应的计数值
;晶振频率为11.0592MHZ
;排列顺序:LSB,MSB
BdTab:DB3Ch,0;02越限,值太小
DB78h,0;12波特率38400
DB0F0,0h;22波特率19200
DB0E0,01h;32波特率9600
DB0C0,03h;42波特率4800
DB80,07h;52波特率2400
DB0,0Fh;62波特率1200
DB0,1Eh;72波特率600
DB0,3Ch;82波特率300
DB0,78h;92越限,值太大
END
3 结束语
最后,需要说明的是:
(1)为确保波特率检测正确,发送一测试字符后,应使数据接收端RXD保持一段高电平,确保T0溢出时所“捕获”到的计数值,是停止位处的T0值。
(2)在实际通讯过程中,如果检测到错误,则应该重新调用该波特率自适应程序,进行波特率再校正。
(3)该软件所采用的“捕获”计数器计数值的方法,可应用到其它波形检测程序中。
■
参考文献
陈 平.串行异步通讯数据的自适应解调方法.电子技术应用,1995,No.10
80C51系列单片机波特率自动检测的通用程序万新恒 龚建明。