整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

C51单片机学习笔记

一. 单灯闪烁 1. 单片机及其外部引脚

单片机是将 CPU、RAM、ROM、定时器/计数器、输入/输出接口电路、中断、串行通 信接口等部件集成在一块芯片上的微型计算机,也称为微控制器。

MCS-51 单片机共有 40 个引脚,其中电源引脚 2 根,外接晶体振荡器引脚 2 根,控制 引脚 4 根以及 4 组 8 位 I/O(输入/输出)引脚 32 根。

(1)主电源引脚(2 根) VCC(40 脚):电源输入,接+5V 电源;GND(20 脚):接地线。 (2)外接晶振引脚(2 根) XTAL1(19 脚):片内振荡电路的输入端;XTAL2(18 脚):片内振荡电路的输出端。

(3)控制引脚(4 根) RST/VPP(9 脚):复位引脚,引脚上出现 2 个机器周期的高电平将使单片机复位。 ALE/PROG(30 脚):地址锁存允许信号。 PSEN(29 脚):外部存储器读选通信号。 EA /VPP(31 脚):程序存储器的内外部选通,接低电平从外部程序存储器读指令,如 果接高电平则从内部程序存储器读指令。

(4)I/O(输入/输出)引脚(32 根) AT89S51 单片机有 4 组 8 位的 I/O 口,分别位 P0、P1、P2、P3 口,每个口有 8 位(8 根引脚),共 32 根;分别为 P0.0~P0.7、P1.0~P1.7、P2.0~P2.7 和 P3.0~P3.7。

2. 单片机最小系统

单片机最小系统(或者最小应用系统)是指用最少的元件组成可以工作的单片机的系统。 对 MCS-51 系列单片机来说,最小系统一般包括:单片机、时钟电路和复位电路。

(1)时钟电路

MCS-5l 单片机内部有一个用于构成振荡器的高增益反相放大器,引脚 XTALl 和 XTAL2 分别是反相放大器的输入端和输出端,由这个放大器与作为反馈元件的片外晶体或陶瓷谐振 器一起构成了一个自激振荡器,如图 1-1 所示,这种方式形成的时钟信号称为内部时钟方式。 电容 C1、C2 一般为 30pF;石英晶振的频率 fosc 为 6MHz、12MHz 和 11.0592MHz 等。

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

(2)复位电路

MCS-51 单片机的 RST/VPD 引脚是复位输入端,在振荡器运行时,RST 端至少要保 持 2 个机器周期为高电平,才完成一次复位。如图 1-2 所示,是上电按键复位电路。一般电 阻 R 可以为 10KΩ,电容 C 为 10uF。

特别注意:对于 31 脚( EA /Vpp),当接高电平时,单片机在复位后从内部 ROM 的 0000H 开始执行;当接低电平时,复位后直接从外部 ROM 的 0000H 开始执行。

3. 单片机与 LED 发光二极管的连接

单片机与 LED 的连接如图 1-3 所示, LED 对应单片机的一个输出引脚。当相应引脚输 出为低电平时,电流从 VCC 流入单片机,LED 开始发光,发光亮度由串联的限流电阻控制; 当相应引脚输出为高电平时,没有电流通过 LED,LED 熄灭。

单片机数字程序显示到指定位置_单片机数字0到9显示程序_单片机数字程序显示到主机

4.代码

#include "reg52.h"
void Delay(unsigned int t);
sbit P00=P0^0;
void main(void){
  while(1){
   P00=1;
   Delay(1000);
   P00=0;
   Delay(1000);
   }
}
void Delay(unsigned int t){
  while(--t);
}

二. 流水彩灯 1.基础学习

单片机数字程序显示到主机_单片机数字0到9显示程序_单片机数字程序显示到指定位置

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

2.代码

//LEDshift .c:LED流水灯程序
//用数组实现循环流水
 #include 
unsigned char code table[8] ={ 0xfe, 0xfd, 0xfb,0xf7,0xef, 0xdf, 0xbf, 0x7f };
void mDelay(unsigned int Delay) //延时程序
{    
     unsigned int i; 
      for(;Delay>0;Delay--)       
      {       for(i=0; i<54; i++)  ;     
      }
}
void main() 
{     
      unsigned char i; 
      while(1)
       {       for ( i =0 ; i<8 ; i++ ) 
               {  
                  P1= table[ i ]; 
                  mDelay(500);                /*延时 500 毫秒*/ 
               } 
       }
}

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

三. 键控灯亮 1.基础

无论单片机对外界进行何种控制,或接受外部的何种控制,都是通过 I/O 口进行的。 MCS-51 单片机总共有 P0、P1、P2、P3 四个 8 位 I/O 口,每个 I/O 口都有锁存器、输出驱 动器和输入缓冲器。

P0 口是 8 位漏极开路型双向 I/O 口,它的作用为:(1)通用 I/O 口:作为输出口时需外 加上拉电阻(1K~10K),作为输入口时先写 1;(2)低 8 位地址/数据分时复用口(单片机系 统扩展时)。

P1 口是内部带上拉电阻的 8 位准双向 I/O 口,它的作用为通用 I/O 口:输出不用外加上 拉电阻,输入也先写 1。

P2 口是内部带上拉电阻的 8 位准双向 I/O 口,它的作用为:(1)通用 I/O 接口:输出不 用外加上拉电阻,输入也先写 1;(2)高 8 位地址口(单片机系统扩展时)。

P3 口是内部带上拉电阻 8 位准双向 I/O 口,它的作为用:(1)通用 I/O 接口:输出不用 外加上拉电阻,输入也先写 1;(2)第二功能:P3.0、P3.1:RxD、TxD(串口接收、发送 端);P3.2、P3.3:INT0、INT1 (外部 0、1 中断);P3.4、P3.5:T0、T1(定时/计数器 0、 1 外部脉冲输入端);P3.6、P3.7:WR 、 RD (片外数据存储器的写、读信号)。

2.代码与连线

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

#include"reg52.h"
#include"intrins.h"
#define uchar unsigned char
#define uint unsigned int
sbit LED0=P1^0;
sbit led1=P2^0;
sbit key=P3^0;
sbit sw=P3^1;
sbit k2=P3^2;
void Delay(uint x){
  uchar i;
  while(x--){
    for(i=0;i<120;i++);
	}
}
void main(){
 while(1){
   if(key) LED0=0;
   else LED0=1;
   if(sw) P0=1;
   else{
      uchar i;
	  P0=0xfe;
	  for(i=0;i<7;i++){
		  Delay(500);
		  P0=_crol_(P0,1);
		  }	  
	}
	if(k2==0){ //按键按下,产生一系列抖动,延时20ms消抖
       Delay(20);
       while(k2==0);//判断按键是否松开。松开则P3_1!=0,跳出循环
       Delay(20);
     //  P2^0 = ~ P2^0;//将LED状态取反
	 led1=~ led1;
     }
	}
}

四.中断系统

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

1.基础学习 1.中断:程序在执行过程中由于外界的原因而被中间打断的情况

中断处理程序(服务):中断之后执行的程序;

主程序:原来运行的程序;

断点:主程序被断开的位置;

中断源:引起中断的原因,或能发出中断申请的来源;

中断请求(申请):中断源要求服务的请求。

中断技术的优点:相对查询方式(查询方式 类似于在while循环中有个if,每次while都会进行if操作,而中断是突发的),cpu效率更高;1.实时处理2.故障处理

中断源:1.外部设备中断源,2.故障源,3.控制对象中断源,4.定时/计时脉冲中断源

中断系统功能:1.能实现中断及返回2.能实现优先权排队3.能实现中断嵌套

2.中断过程:中断请求>中断响应>中断处理

中断响应:条件:中断标志是否开放,是否高级中断,是否执行完一条指令等。

中断处理:1.保护现场:根据需要把断点处有关存储器的内容压入堆栈,以保护主程序运行结果。

2.开/关中断标志:根据cpu响应中断后开/关中断情况,适当处理中断标志,以确保保护/恢复现场的正确进行,确保所需中断嵌套的实现。(当中断来的时候,若中断标志未开,则此次中断失败)

3.中断处理

4.恢复现场:在完成中断服务之后,返回被中断的主程序之前,恢复堆栈中保护的各有关寄存器的内容。

3.中断返回:

中断服务程序最后,用一条中断返回指令(RETI),保证返回主程序继续执行被中断的程序。

4.进一步认识

中断源:51系列有5个 ,52系列有6个

5个中断源:2个外部中断源,2个定时中断源,1个串行口中断源

单片机数字程序显示到主机_单片机数字0到9显示程序_单片机数字程序显示到指定位置

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

5.中断优先级

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

6.语法函数

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

7.注意

单片机数字程序显示到主机_单片机数字0到9显示程序_单片机数字程序显示到指定位置

单片机数字程序显示到主机_单片机数字0到9显示程序_单片机数字程序显示到指定位置

2.实操代码

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

#include 
void mDelay(unsigned int Delay)   
{  
      unsigned int data i; 
	for(;Delay>0;Delay--) 
 	{ 
		for(i=0; i<54; i++)   ;
 	}
}
void main() 
{  	IT0=1;			//外部0中断边沿触发
	EA=1;			//开总中断
	EX0=1;			//开外部0中断
    	while(1) 
    	{	P1=0xff;  	 //8个LED熄灭
	}         
}
void ex0_int() interrupt 0
{
	unsigned char data j;		
	for(j=0;j<6;j++)
    	{  
		P1=0x00;	//8个LED点亮
       		mDelay(1000);	//延时1000ms
       		P1=0xff;	//8个LED熄灭
       		mDelay(1000);	//延时1000ms  
	}
}

五. 定时/计数器

作为定时器时,它是对机器周期计数,即对片内振荡器输出的时钟信号经12分频后的脉冲计数,即一个机器周期计数器的数值加1。作为计数器时,它是对引脚T0(P3^4)和T1(P3^5)上的外部脉冲信号计数。当外部输出产生由高电平至低电平的下降沿时,计数器加1。此实验重点在于代码的掌握和配置。了解计数与定时原理、会计算初值并赋予、掌握TMOD和TCON。

1. 基础认识

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

1.工作方式寄存器(TMOD)(不能位寻址)

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

GATE:门控位。当GATE=0时,为软件启动,当GATE=1时,为硬件启动。(课程为软件启动)

:定时或计数功能选择位。1为计数方式,0为定时方式。

工作方式1常用,最大脉冲个数65536(

工作方式2常用,最大脉冲个数256(

),自动重装

2.控制寄存器(TCON)(可以位寻址)

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

TF0(TF1):定时器/计数器T0(T1)计数溢出标志位。 =1 计数溢出; =0 计数未满。此标志位可用于申请中断或供CPU查询。中断方式:自动清零;查询方式:必须软件清零。

TR0(TR1):运行控制位。=1 启动计数; =0 停止计数。该位由软件进行置位/清零。

IE0(IE1):外部中断0/1请求标志。 =1 存在中断请求; =0 无中断请求。

IT0(IT1);外部中断触发方式选择。 =1 低电平触发; =0 下降沿触发。

3.初值寄存器(TH1、TL1,TH0、TL0)

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

fosc=12MHz,1Tm=1us,

2.定时器

流程为:计算计数初值,TMOD初始化,启动和停止控制,中断的开放/禁止

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

方式1:

#include "reg51.h"
#define uchar unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
                              //数码表
uchar int count,t1,t2;
void main(){
     TMOD=0x10;               //选用T1,工作方式2
	 TH1=65536/256;           //初值高位 理论此时应已溢出,但由于若输入x为0,则错误,输入65536却达到效果
	 TL1=65536%256;           //初值低位
	 EA=1;                    //开全中断
	 ET1=1;                   //开定时器1中断
	 TR1=1;                   //启动定时器
	 
	 while(1){;}
	 }
void T1_int() interrupt 3{
     TH1=65536/256;           //再次赋值
	 TL1=65536%256;
	 count++;
	 t1=count0/15;         //计算出1s
	 t2=count/150;
	 P0=table[t1];            //显示
	 P2=table[t2];
	 }

方式2:自动重装

# include 
sbit LED1=P1^0;
void main()
{  
   TMOD = 0x02; //定时方式2
   TH0 = 0x06;     //置初值
   TL0 = 0x06;
   EA = 1; ET0 = 1;    //开T0中断
   TR0 = 1;          //启动T0
   while(1)  { ; }    
}
void T0_int( ) interrupt 1
{
    LED1 =!LED1;      //LED取反
}

3.计数器 4.课外拓展

1.产生占空比可调的矩形波

#include  // 包含51单片机的头文件,定义了单片机的寄存器和位操作等功能
sbit LED0 = P1^0; // 定义P1口的第0位为LED0,用于控制一个LED灯
unsigned int i; // 定义一个无符号整型变量i,用于计数
void main() // 主函数
{
    TMOD = 0x01; // 配置定时器/计数器模式寄存器TMOD,设置定时器0为模式1(16位自动重装载)
    TH0 = 65286 / 256; // 给定时器高位寄存器TH0设置初始值,这里用于预设一个较大的延时以初始化
    TL0 = 65286 % 256; // 给定时器低位寄存器TL0设置初始值,配合TH0完成初始值设置
    EA = 1; // 开启全局中断允许
    ET0 = 1; // 允许定时器0中断
    LED0 = 0; // 初始化时LED灯为熄灭状态
    i = 0; // 初始化计数器i
    TR0 = 1; // 启动定时器0
    while(1) { ; } // 无限循环,程序主要行为由中断服务程序控制
}
void T0_int() interrupt 1 // 定时器0中断服务程序
{
    i++; // 每次进入中断,计数器i加1
    if(i % 2 == 0) // 如果i是偶数
    {
        TH0 = (65536 - 500) / 256; // 重新设置定时器初值,使得定时时间为500us(高字节)
        TL0 = (65536 - 500) % 256; // (低字节),用于控制LED较慢闪烁的周期
        LED0 = 1; // 切换LED状态为亮
    }
    else
    {
        TH0 = (65536 - 250) / 256; // 重新设置定时器初值,使得定时时间为250us,用于较快闪烁的周期
        TL0 = (65536 - 250) % 256;
        LED0 = 0; // 切换LED状态为熄灭
    }
}

2.对P3.4引脚的输入信号进行二分频

#include  // 包含头文件,该文件定义了51单片机的特殊功能寄存器和位定义等。

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

sbit LED0 = P1^0; // 定义P1口的第0位为LED0,通常用来控制一个LED灯的亮灭。 void main() // 程序的主函数 { TMOD = 0x60; // 配置定时器模式寄存器TMOD,设置定时器T1为模式2(自动重装载8位计数器)。 TH1 = 255; // 设置定时器T1的高8位初值为255,与TL1一起构成256计数值,因为是模式2,所以这是最大计数值。 TL1 = 255; // 设置定时器T1的低8位初值也为255,与TH1相同原因。 EA = 1; // 开启全局中断允许位。 ET1 = 1; // 允许定时器T1中断。 LED0 = 0; // 初始化LED0为熄灭状态。 TR1 = 1; // 启动定时器T1。 while(1) { ; } // 无限循环,程序的主要逻辑由中断服务程序处理。 } void T1_int() interrupt 3 // 定时器T1的中断服务程序,中断号为3。 { LED0 = !LED0; // 切换LED0的状态,如果之前是亮则变为灭,反之亦然。 }

六. 串行通信接口

51单片机内有一个通用全双工串行口,可以四种工作模式和不同的波特率工作。串行通信分为同步通信和异步通信,同步通信按数据块传输,对硬件要求高,课程采用异步通信,按字符传输。串行通信的重点在于代码和波特率控制。首先根据波特率计算出T1的初值,配置TMOD、TH1、TL1、TR1,若TMOD=0x20,则表示选择T1方式中的工作方式2,TLx具有自动重装初值的8位定时器/计数器,THx为初值寄存器。再配置SCON、PCON、EA、ES,若SCON=0x50,则表示串口工作方式为1,且REN=1;PCON的首位是SMOD,是波特率的控制位,1表示波特率加倍,0表示波特率不加倍;ES=1且EA=1表示串行中断打开,中断的作用是,当接收移位寄存器接收完一帧的数据后,RI=1,申请中断,通知CPU从SBUF中取走数据。

1.基础配置学习 1.串行通信的两种形式

并行通信只适合短距离通信,速度快效率高,需要数据线条数多。串行通信分为异步通信和同步通信。

同步通信:一般一次传送一个数据块。每个数据块的开头以同步字符SYN加以指示使发送方和接收方取得同步。数据块的各字符间没有起始位和停止位,提高了通信速度。但为了能保持同步传送,接受与发送双方必须用一个时钟来协调收发器的工作,这就增加了设备的复杂性。

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

异步通信:发送和接受方采用独立时钟。一帧信息表示一个字符,一帧信息包括起始位(为0信号,占一位)、数据位(传输时低位在先,高位在后)、奇偶校验位(可要可不要)、停止位(为1信号,可1位、1位半或2位)

单片机数字程序显示到指定位置_单片机数字0到9显示程序_单片机数字程序显示到主机

在串行通信中,通信双方事先应该做好一下约定:

1.字符格式。双方要事先约定字符的编码形式、奇偶校验形式、起始位、停止位的规定。例如,用ASCII码通信,有效数据为7位,加一个奇校验位、一个起始位、一个停止位共10位。

2.波特率。波特率就是数据的传送速率,即每秒传送的二进制数位数,单位为位/s,即1波特=1b/s。在异步通信中,发送端和接收端的波特率必须一致。

2.串行通信模式(单工、半双工、全双工)

三种传输方式都是用同一线路传输一种性质的信号,为了充分利用线路资源,可通过使用多路复用器或多路集线器,采用频分、时分或码分复用技术,实现在同一线路上的资源共享,称为多工传输方式。

3.SCON与PCON(核心控制)

在串行通信时,用串行通信控制寄存器SCON和电源控制寄存器PCON控制串行接口的工作方式和波特率。

1.认识寄存器(SBUF)

51单片机串行接口有一个发送缓冲器和一个接收缓冲器。发送缓冲器只能写入信息,用于存储发送信息。接收缓存器只能读出信息,用于存储接受到的信息。此外,接收缓冲寄存器与发送缓冲寄存器共用一个地址,但由于操作是独立的故不会发生冲突。(老师解释,类似于一个门牌号,两个房间。)对接收/发送缓冲寄存器SBUF的操作,无论是否采用中断方式工作,每接收/发送一个数据都必须用指令对串行中断标志RI/TI清零,以备下一次接收发送能正确进行。

接收方式:串行数据通过引脚RXD(P3^0)进入。接收寄存器之间还有移位寄存器,从而构成双缓冲结构,避免出现帧重叠错误,即在下一帧数据来时,前一帧数据还没有读走。

发送方式:串行数据通过TXD(P3^1)送出。发送数据时,由于CPU是主动的,不会发生帧重叠错误,发送电路不需要双缓冲结构,可以提高发送数据发送速度。

2.控制寄存器(SCON)

1.工作方式

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

方式0:8位同步移位寄存器。

课程以工作方式1为主,10位UART(8位通用异步接收器/发送器),波特率T1溢出率/n。(当SMOD=1时,n=16;当SMOD=0时,n=32。)方式1在应用上,只能用于双机通信,不能用于多机通信。

方式2:11位UART,波特率与SMOD有关。

单片机数字程序显示到主机_单片机数字0到9显示程序_单片机数字程序显示到指定位置

方式3:11位UART,波特率可调。除波特率外,同方式2。

2.SCON 98H(其他位的认识)

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

3.波特率计算(1s内串口出去的位数)

定时器的溢出率是指1s内产生溢出的次数。T1作波特率发生器时,用定时方式2(自动重装功能)可以避免通过程序反复装入初值所引起的定时误差,使波特率更加稳定。

定时器每秒所溢出的次数为 (1/溢出周期):

单片机数字程序显示到指定位置_单片机数字0到9显示程序_单片机数字程序显示到主机

溢出率:

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

先确定波特率,再计算T1的计数初值,然后进行T1的初始化(初值):

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

3.电源控制寄存器(PCON)

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

PCON的字节地址为87H,没有位寻址功能。主要实现对单片机电源的管理控制。

SMOD:是串行口波特率系数控制位。为1时,串行口波特率加倍。系统复位时,SMOD=0.

4.中断允许寄存器IE

ES=0 禁止串行中断

ES=1 允许串行中断

EA=0 禁止中断

EA=1 允许中断

2.实操(连接原理图,代码分析,效果展示)

单片机数字程序显示到主机_单片机数字0到9显示程序_单片机数字程序显示到指定位置

代码分析

#include"reg51.h"
#include"intrins.h"
unsigned char data senddata,sendcnt,recvdata,d;
void Delay(unsigned int x){
     unsigned char i;
	 while(x--){
	     for(i=0;i<120;i++);
	 }
}
void main() { // 主函数开始
    TMOD=0x20; // 配置定时器模式寄存器TMOD。这里设置为模式2,用于自动重装载的方式工作,常用于波特率发生器。
    
    TL1=0xFD; // 设置定时器1的低8位初值。与TH1一起用于设定串口的波特率。
    TH1=0xFD; // 设置定时器1的高8位初值。注意:实际的初值应根据系统时钟和所需的波特率计算得出。
    
    TR1=1; // 启动定时器1。
    
    SCON=0x50; // 配置串行口控制寄存器SCON。这里设置了工作于模式1(8位UART,可变波特率),并且允许接收。
               // 具体来说,0x50 = 0b01010000,其中SM0=0, SM1=1选择模式1,REN=1允许接收。
    
    PCON=0x00; // 设置电源控制寄存器PCON。这里清零,表示不使用掉电模式或双速模式。
    
    senddata=06; // 定义并初始化要发送的数据为十六进制的06(十进制中的6)。
    
    EA=1; // 开启全局中断允许位。
    ES=1; // 开启串行口中断允许位,以便在发送完成或接收到数据时产生中断。
    
    SBUF=senddata; // 将数据送入串行口缓冲器SBUF,准备发送。
    
    while(1){;} // 进入无限循环,等待中断发生。主要因为主程序在此处不再执行其他操作,依赖中断处理后续任务。
} // 主函数结束
void ser_int() interrupt 4{   //串行中断
     if(RI){                  // 如果是接收中断请求标志RI被置位(即有数据接收)
	     P0=SBUF;              // 将接收到的数据暂存到P0端口
		 switch(SBUF){        // 根据接收到的数据(现在在SBUF中)执行不同的操作 
		  case 1:{
		       P1=0xff;
			   Delay(500);
			   P1=0x00;
			   Delay(500);
			   P1=0xff;
			   Delay(500);
			   P1=0x00;
			   Delay(500);
		 };break;
		  case 2:{
		       P1=0x00;
		 };break;
		  case 3:{
		       P1=0xfe;
			   while(1){
			        for(d=0;d<7;d++){
					     Delay(500);
						 P1=_crol_(P1,1);
					}
					break;
				}
		 };break;
		 }
		 RI=0;               // 清除接收中断标志位
	  }else if(TI){           // 如果是发送中断请求标志TI被置位(即数据发送完毕)
	     TI=0;               // 清除发送中断标志位
		 SBUF=senddata;       // 发送数据
		}
}

单片机数字程序显示到主机_单片机数字0到9显示程序_单片机数字程序显示到指定位置

3.胡老师文件

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

#include 
unsigned char data  Senddata,Sendcnt;  //全局变量,在所有程序里有效
void main()
{
    TMOD=0x20; TL1=0xfd;  TH1=0xfd;  TR1=1; //初始化T1,波特率9600
    SCON=0x50;   PCON=0x00;      			//初始化串口,方式1,接收数据
    Senddata=1;  Sendcnt=10;         		//发送数据为1,字节数为10
    EA=1;  ES=1;                            //开串口中断    
    SBUF=Senddata;                        	//发送数据给SBUF
    while(1) ;                              //等待串口中断
}
void ser_int( ) interrupt 4     	//串口中断服务子程序 
{    
	if(RI)                 			//是接收中断
    {     
		P2=SBUF;              		//读取SBUF数据送P1口显示            
		RI=0;                      	//清接收中断标志位
    }
    else if(TI)            			//是发送中断
    {      
		TI=0;                       //清发送中断标志位
        Sendcnt--;               	//发送字节数减1
        if(Sendcnt!=0)        		//没有发送完10个字节
        {     
			Senddata++;         	//发送数据加1
            SBUF=Senddata;     		//发送数据送SBUF
        }
    }
}

七. LED数码管显示器接口

数码管分为共阴和共阳,共阴和共阳分别有自己的显示代码表;显示分为动态显示和静态显示,动态显示要用数组调动好显示代码表,掌握对要显示位的变换方式(动态显示某一位),要刷新好位的显示。

1静态显示(通过编码使数码管显示数字) 1.要显示字符时,相应的发光二极管恒定的导通或截至,直到显示另一个字符。

优点:亮度较高,编程容易,管理较简单。

缺点:占用I/O口资源较多,每位占用8根I/O线。

连接:每位的每根段选(发光二极管)连接一根I/O线。

应用:一般用于显示位数较少的场合。在显示位数较多时,一般采用动态显示。

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

2.段选码表

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

3.代码分析

#include 
unsigned char code dis_tab[16]={0xC0,0xF9,0xA4,0xB0, 0x99,0x92,0x82,0xF8
,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E} ;
                            //显示代码表,共阳
void main()
{
    while(1)
    { 
          P1 = dis_tab[1];  //P1显示1
          P2 = dis_tab[2];
          P3 = dis_tab[3];
    }
}

4.串行扩展LED显示器静态(未练习)

可进位

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

2. 动态显示(利用视觉原理,使每位数字在同一时间内闪烁30多次,达到视觉常亮的目的)

以静态显示为基础

1.基础认识

基本特点:一位一位地分时轮流点亮各位显示器,对每一位显示器来说,每隔一段时间轮流电 亮一次。

显示亮度:显示器的亮度既与导通电流有关,也与点亮和熄灭时间的比例有关。

连接方式:将LED数码管显示器的所有段选位并联在一起,由一个8位I/O口控制。 公共端分别由相应的I/O口控制,实现各位显示器的分时选通。

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

2.代码解析与仿真图记录

#include 
#include 
unsigned char code dis_tab[16]={0x3f,0x06,0x5b,0x4f,0x66, 0x6d, 0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71} ;
                             //显示代码表,共阴
unsigned char data dis_data,bit_data;
void mDelay(unsigned int Delay)
{   unsigned int i;
    for(;Delay>0;Delay--)
    {   for(i=0;i<114;i++)  {;}
    }
}
void display()               //显示函数
{  unsigned char i;
   bit_data = 0xfe;          //设置初始位选数据
   dis_data = 1;
   for(i=0; i<6; i++)
   {   
       P2 = 0xff;            //刷新,全灭
       P1 = dis_tab[dis_data];//P1输出 这个数
       P2 = bit_data;        //设置初始位
       mDelay(5);          
       bit_data =_crol_( bit_data , 1 );   //位选码左移1位
       dis_data ++;          //加1,到数组下一个数
   }
}
void main()
{   
    while(1)
    {     
         display();   
     }
}

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

3.补充说明

未仿真Lcd1602

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

八. 键盘接口

键盘分为独立式键盘和行列式键盘,按照按键识别方式分为编码键盘(由硬件识别键的闭合)和未编码键盘(由软件识别键的闭合)。按键开关会产生抖动,要消抖,消抖分为软件消抖和硬件消抖,学习过程中常用软件消抖。键盘扫描的工作方式有三种,首先分为查询扫描方式和中断扫描方式,查询扫描方式又分为定时查询和实时查询。先讲独立式键盘,课程主要学习了独立式键盘,未实践矩阵式键盘。

1.独立式键盘 1.基础知识 1.消除抖动(课程中主要采用软件消抖,即延时消抖)

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

单片机数字程序显示到指定位置_单片机数字0到9显示程序_单片机数字程序显示到主机

硬件消抖:RS触发器(详细原理未说明)

软件消抖:延时5~10ms左右再测

2.键盘扫描工作方式 1.实时查询(单片机一直循环执行查询程序进行查询)

键盘扫描一般包括四个步骤:

1.判断键盘有无键按下。

2.去除按键抖动

3.求键值(键号)。在矩阵式键盘中,闭合按键的键号可以用公式获得。

4.判断按键是否释放。按键闭合一次仅进行一次按键功能操作,等按键释放以后再执行按键指定功 能操作。

2.定时查询(每隔固定时间间隔查询一次或每到固定时间查询一次)

以实时查询为基础,使用定时/计数器功能,在实时查询函数外加上延时或定时函数。

3.中断查询(只有中断产生时,即键盘按下时,才会扫描键盘)

实际应用中按键并不经常工作,此方法既能即时处理键盘输入,又能提高CPU效率。

2.原理图与代码分析

此原理图包括中断方式:

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

# include 
sbit K0=P1^0;                 //定义按键所连I/O口
sbit K1=P1^1;
sbit K2=P1^2;
//延时子程序:由Delay参数决定延时时间
void mDelay(unsigned int Delay)   
{    
     unsigned int i; 
      for(;Delay>0;Delay--)
      {    for(i=0;i<114;i++)   ;
      } 
}  
//按键扫描子程序,判断按键是否按下,如果按下并处理
void keyscan(void){

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

if(!K0){ //K0按键是否按下 mDelay(5); //延时消抖 if(!K0) { //K0按键确实按下,进行处理 ... ; while(!K0); //等待K0按键释放 } } if(!K1){ //K1按键是否按下 mDelay(5); //延时消抖 if(!K1){ //K1按键确实按下,进行处理 ... ; while(!K1); //等待K1按键释放 } } if(!K2){ //K2按键是否按下 mDelay(5); //延时消抖 if(!K2){ //K2按键确实按下,进行处理 ... ; while(!K2) ; //等待K2按键释放 } } } void main(void) { while(1) { P1=0xff; //设置P1为输入方式 keyscan(); } }

2. 矩阵式键盘(未实操,仅原理图)

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

单片机数字程序显示到主机_单片机数字0到9显示程序_单片机数字程序显示到指定位置

# include 
//延时子程序:由Delay参数决定延时时间
void mDelay(unsigned int Delay)   
{    unsigned int i; 
      for(;Delay>0;Delay--)
      {    for(i=0;i<114;i++)  {;}
      } 
}  
//按键扫描子程序,有键按下,返回键值00-15;无键按下,返回0xff。
unsigned char Matrix_key(void)
{     
    unsigned char key, temp1,temp2;
    key=0xff;			// 初始化键值
    P2=0x0f;			// 输出列扫描字
    if( (P2&0x0F) !=0x0f)	// 读行线状态,判断是否有键按下
    {       
	mDelay(10); 		// 延时消抖
	P2=0x0f;		// 输出列扫描字
    temp1=P2&0x0f;           // 读行线状态到temp1中
    if( temp1!=0x0f )                           	// 有键按下
        {   P2=0xf0;				// 输出行扫描字
            temp2=P2&0xf0;			// 读列线状态到temp2中
            switch( temp1|temp2 )
            {   case 0xee:key=0; break;		
                case 0xde:key=1; break;
                case 0xbe:key=2; break;
                case 0x7e:key=3; break;                      
                case 0xed:key=4; break;
                case 0xdd:key=5; break;
                case 0xbd:key=6; break;
                case 0x7d:key=7; break;
                case 0xeb:key=8; break;
                case 0xdb:key=9; break;
                case 0xbb:key=10;break;
                case 0x7b:key=11;break;
                case 0xe7:key=12;break;
                case 0xd7:key=13;break;
                case 0xb7:key=14;break;
                case 0x77:key=15;break;
                default: key=0xff;  break;            }       }	}
    else      { ; }
    return ( key );      //返回键值
} 
void main(void)
{  unsigned char key_value; 
   while(1)
    {   
        key_value = Matrix_key();      //调用按键识别子程序
        switch(key_value)                  //根据按键分支
        {   
            case 0: P0=0xfe; break;     //0号按键,LED1点亮
            case 1: P0=0xfd; break;     //1号按键,LED2点亮
            case 2: P0=0xfb; break;     //2号按键,LED3点亮
            case 3: P0=0xf7; break;     //3号按键,LED4点亮
            case 4: P0=0xef; break;     //4号按键,LED5点亮
            case 5: P0=0xdf; break;     //5号按键,LED6点亮
            case 6: P0=0xbf; break;     //6号按键,LED7点亮
            case 7: P0=0x7f; break;     //7号按键,LED8点亮
            default: break;                    //无效按键            
        }
    }           
}
                    

九. 存储器扩展

包括ROM程序存储器(存储)和RAM数据存储器(内存),重点在对引脚的认识和对存储器的认识,然后正确的连接,代码是次要的。

1.初步认识

51单片机的内部资源(RAM、ROM、I/O、A/D、D/A等)不足时,需要扩展。

对51单片机来说,并行存储器扩展的基本原则时:P0口提供数据线;P2、P0口提供地址线,其中低位用于片内选择,高位用于芯片选择;用

控制程序存储器的读操作,用

控制数据存储器读写操作。

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

1.存储器扩展的基本方法(总线扩展法)

数据总线(用于单片机与存储器的数据传送):由P0口提供。芯片数目计算(没有写)。

地址总线(用于寻址存储单元):由P0口和P2口共同提供。由于P0口是分时复用传递地址和数据信息,所以当P0口传送地址信息时,常用ALE信号控制地址锁存器对P0口提供的低8位地址A0~A7进行锁存后输出,与P2口输出的高8位地址组成16位总线。

控制总线(用于协调控制数据信息与地址信息的正确传送):

ALE:地址锁存控制。ALE的下降沿控制锁存器锁存P0口输出的低8位地址,与74LS373的 使能端相连。

:程序存储器ROM的读控制信号。执行程序存储器读指令MOVC时,该信号有效, 与程序存储器输出使能端相连。

:程序存储器选择。低电平表示系统从片外程序存储器0000H开始读程序;高电平表示 系统从片内程序存储器0000H开始读程序,超出片内程序存储器的范围后,自动转到 片外程序存储器。

:片外数据存储器的读写控制。执行片外数据存储器读写指令MOVX时,信号有 效,分别与存储器扩展芯片的输出使能和写使能端相连。

2. 选通方式

存储器扩展芯片的芯片选通线通常由高位地址线直接选通或经地址译码器译码后选通。

线选法:先将扩展储存器芯片的地址线与单片机的地址总线从低位开始顺次相连后,剩余的高位地址线的一根或几根直接连接到各扩展存储器的片选线上。【一般片选端(

等)低电平有效,只要连接片选信号端的引线状态位为低电平,就表示选中该芯片。高位地址线A13~A15中,同一时刻只允许有一根线为低电平,另外两根必须为高电平,否则出错。】

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

译码选择法(包括部分译码和全译码):类同上,将地址总线连好后,剩余的高位地址线,连接译码器,从译码器的输出端的选中的输出引脚输出一个0,进而选中芯片。如果将剩余的高位地址线全部连接到译码器,则为全译码法,若没有,则为部分译码法。(部分译码法仍然会像线选法一样造成重叠,若有N条高位地址线不参加译码,则有2的N次方个重叠,重叠的地址真正能存储信息的只有一个,因而会造成浪费。在存储器扩展容量不大的情况下,选择线选发,电路会简单些,可降低成本;当扩展较大时,选择全译码法,可消除地址重叠,充分利用存储空间。)

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

2.进一步认识(对芯片的认识)

对于8051单片机,只要加上振荡电路和复位电路,该系统就可以工作了,常称这样的系统为最小系统。对于不带片内ROM的单片机,如8031,8032,必须在片外扩展ROM之后才能构成最小系统

1.ROM 程序存储器(储存):

EPROM:紫外线可擦除电可编程的半导体只读存储器,掉电后信息不会丢失。(EPROM中的程序由专门的编程器写入,由专门的擦除器擦除,擦除后全为1状态。擦除时紫外线强度为12000mw/cm2,波长为I=2537A,时间为10~20min。)常用的EPROM有:2716、2732、2764...

:电可擦除电可编程,掉电后信息不丢失;编程简单,不需要专门的编程器和擦除器;兼有RAM和ROM的特点,故既可做ROM也可做RAM;常用的并行E2PROM有2816、2864

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

2. RAM 数据存储器(内存):

51单片机内部有256B的RAM存储器,但对需要大容量数据缓冲器的应用系统(如数据采集系统),就须外部扩展RAM。常用的半导体静态随机存取存储器SRAM,如6116,6264,62256。

也可作外部RAM(但速度慢),但因它掉电后信息不丢失,对某些要求不间断工作、对于一些关键性的实时数据不允许丢失的场合较合适。

单片机数字程序显示到指定位置_单片机数字0到9显示程序_单片机数字程序显示到主机

单片机数字程序显示到主机_单片机数字0到9显示程序_单片机数字程序显示到指定位置

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

3. 编程和使用

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

1.RAM举例(6264)

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

#include"reg51.h"
unsigned char code *point1;
unsigned char xdata *point2;
void main(){
     char i;
     while(1){
	       point1=0x20;               //定义point1的位置
		   point2=0x40;
		   for(i=0;i<5;i++){
		        
		        *point2=*point1;      //使point2位置的数据等于point1位置的数据
				point1++;             //point1位置延1
				point2++;
			}
	 }
}

十. 并行I/O口扩展

与存储器类似。由于51只有四个I/O口,会不够用,类似于存储器对外部的寻址和数据读写,进行扩展。以51和74LS373同74LS244的实验来看,51的P0口同时与373和244连接,再373接灯,244接开关,当开关按下时,244将信号0发送给P0口,51单片机接收并输出给373,而后灯亮。

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

1. 74LS373与74LS244

1. 74LS373 74LS373 是一种 3 态输出的 8D 触发器,它的 OE 端和 LE 端是控制端,当它的 OE 端 为低电平时只要在 LE 端产生一个正跳变,D0~D7 将被锁存到 Q0~Q7 端输出,在其它情 况下 Q0~Q7 端的输出保持不变。可以利用 74LS373 这一特性扩展并行输出口,图 10-1 使 用一片 74LS373 扩展输出口,如果将未使用到的地址线都置为 1,则可以得到该片 74LS377 的地址为 7FFFH。如果单片机要从该片 74LS373 输出数据,可以执行如下指令:

char xdata * = 0x7fff;

char data Outdata;

* = Outdata;

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

2. 74LS244 74LS244 是一种三态输出的八总线驱动器,无锁存功能。它的 OE 端是控制端,当它的 OE 端为低电平时,则 74LS244 将 A 端数据传送至 Y 端;在其它情况下不传送数据,并输 出高阻态。可以利用 74LS244 这一特性扩展并行输入口,图 10-2 使用一片 74LS245 扩展输 入口,如果将未使用到的地址线都置为 1,则可以得到该片 74LS244 的地址为 BFFFH。如 23 果单片机要从该片 74LS244 读取数据,可以执行如下指令:

char xdata * = 0xbfff;

char data Indata;

Indata = *;

2.实操

接线图和代码

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

3.注意

单片机数字程序显示到指定位置_单片机数字0到9显示程序_单片机数字程序显示到主机

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

特点:电路简单、成本低、配置灵活

输出接口:由于大多数外设速度远远低于CPU速度,输出接口电路必须有锁存功能,锁存CPU给外设的数据,以便外设慢慢处理。

输入接口:由于大多数外设没有3态缓存功能,而挂在数据总线的输出端必须有三态缓存功能,故输入接口电路必须有三态缓存功能。

1.74373(是一种8D锁存器)

单片机数字0到9显示程序_单片机数字程序显示到指定位置_单片机数字程序显示到主机

单片机数字程序显示到指定位置_单片机数字0到9显示程序_单片机数字程序显示到主机

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

2.74244是一种三态输入8总线收发器/驱动器,无锁存功能。可作为常态数据输入设备的输入接口

十一. A-D转换

A-D转换器是将模拟信号转换成数字信号的器件,以ADC0809为例(与ADC0808区别很小)

1基础认识

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

此ADC可大致分为三个部分,

1.输入切换(模拟量进入ADC的入口)

ALE:地址锁存允许信号输入端。ALE信号有效时,将当前地址锁存。

ADD C、B、A : 八路模拟信号选择端。地址编码000~111(二进制)表示IN0~IN7八路A-D通道。

2.A/D转换(ADC的核心,接受输入的模拟量,进行逐次比较,并输出数字量给输出接口输出)

积分型AD

ms(低速)

精度高,抗干扰能力强,价格便宜,速度慢,应用于数字仪表(电容充放电需要时间)

逐次比较型AD

us(中速)

抗干扰能力弱,其他适中(逐个比较)

并行型AD

ns(高速)

高速电路(飞机、军工等高科技产业运用,价格贵)

START:启动A-D转换信号输入端。当START输入一个正脉冲时,启动ADC0809开始A-D转换。

EOC:A-D转换结束信号输出端,高电平有效。EOC=0,正在进行转换;EOC=1,转换结束。(该 状态信号既可作为查询的状态标志,又可作为中断请求信号使用)

CLOCK:外部时钟输入端。时钟频率高,A-D转换速度快,允许范围为10~1290kHz。(通常将 8051单片机的ALE端直接或分频后与ADC的CLOCK连接。)

VREF(+)、VREF(-):正负基准电压输入端。(接A-D转换器的256电阻阶梯)

单片机数字程序显示到主机_单片机数字程序显示到指定位置_单片机数字0到9显示程序

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

3.输出接口(输出数字量给单片机,由单片机进一步处理)

OE:A-D转换结果输出允许控制端。OE=1,允许A-D转换结果从D0~D7端输出。

D0~D7:数字量输出端。为三态缓冲输出形式,可以和单片机的并行数据线直接相连。

2.代码分析与原理图连线

原理解析

通电后,首先由ADC0808的已被选中的模拟信号输入端输入电信号,然后经ADC0808内部处理输出数字量,将数字量输入到单片机中,如图输入P1口,对数据进行处理后,再通过单片机内部的程序,动态显示出来。

原理图连线(未使用74HC373和D锁存器)

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

代码分析

# include 
#define uchar unsigned char            //定义uchar为无符号字符数据类型
const unsigned char LED_TAB[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
                                       //显示代码
sbit OE=P3^0;
sbit EOC=P3^1;
sbit ST=P3^2;
sbit ADDA=P3^4;                        //通道选择
sbit ADDB=P3^5;
sbit ADDC=P3^6;
uchar ADC,datal[3];                    //存放ADC转换后的数据
void delay_lms(void){
     unsigned char temp = 249;
	 while(--temp);
	 temp=249;
	 while(--temp);
}
void display(void){                    //定义显示函数
     unsigned char i;
	 unsigned char dsSel =0xfd;        //显示位初值
	 datal[0]=ADC/100;                 //ADC转化后的数据的百位
	 datal[1]=ADC0/10;              //
	 datal[2]=ADC0;              //
	 for(i=0;i<3;i++){
	     P2=dsSel;                     //将显示位送到P2口,依次显示百、十、个位
		 P0=LED_TAB[datal[i]];         //送显示代码到P0口
		 delay_lms();                  //延时1ms
		 dsSel<<=1;                    //显示位左移一位
		 dsSel|=0x01;                  //最低位置1
	 }
}
void main(void){
     while(1){
	     ADDA=1;                       //选择通道3
		 ADDB=1;
		 ADDC=0;
		 ST=0;ST=1;ST=0;               //START正脉冲,启动ADC开始转换
		 while(EOC==0);                //等待转换结束
		 OE=1;                         //允许输出
		 ADC=P1;                       //转换结果存储到ADC单元
		 OE=0;                         //关闭输出
		 display();                    //调用显示程序
	 }
}

十二. D-A转换

将数字信号转换成模拟信号,输出是电压或电流信号

1.基础认识(以DAC0832为例 由数据锁存器与DAC寄存器构成两级数据输入锁存)

单片机数字程序显示到指定位置_单片机数字程序显示到主机_单片机数字0到9显示程序

单片机将数据发送给数据锁存器,再到DAC寄存器,再到D/A转换器

1.转换的核心在D/A转换器

单片机数字0到9显示程序_单片机数字程序显示到主机_单片机数字程序显示到指定位置

VREF(Ur):基准电压输入端,可在-10V~+10V范围内调节。

深入理解51单片机串口通信及通信实例

串口通信的原理

串口通信()的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488定义并行通行状态时,规定设备线总长不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。典型地,串口用于ASCII码字符的传输。通信使用3根线完成,分别是地线、发送、接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。

读取错误数据或已损坏_读取意外错误包数据的软件_意外的数据包读取错误

a,波特率:这是一个衡量符号传输速率的参数。指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。一般调制速率大于波特率,比如曼彻斯特编码)。通常电话线的波特率为14400,28800和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。

b,数据位:这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。如果数据使用简单的文本(标准ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。

c,停止位:用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

d,奇偶校验位:在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位为1,这样就有3个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。

RS232概述

在我们电脑上,一般都会有一个9针的串行接口,这个串行接口叫做RS232接口,它和UART通信有关联,但是由于现在笔记本电脑不带9针串口,所以和单片机通信越来越趋于使用USB虚拟串口。

九针串口分工头和母头

公头上5下4,上5从左到右为1.2.3.4.5;下4从左到右为6.7.8.9;

母头上5下4,上5从左到右为5.4.3.2.1;下4从左到右为9.8.7.6;

RS232接口一共有9个引脚,分别定义是:1、载波检测DCD;2、接收数据RXD;3、发送数据TXD;4、数据终端准备好DTR;5、信号地线SG;6、数据准备好DSR;7、请求发送RTS;8、清除发送CTS;9、振铃提示RI。我们要让这个串口和我们单片机进行通信,我们只需要关心其中的2脚RXD、3脚TXD和5脚GND即可

虽然这三个引脚的名字和我们单片机上的串口名字一样,但是却不能直接和单片机对连通信,这是为什么呢?随着我们了解的内容越来越多,我们得慢慢知道,不是所有的电路都是5V代表高电平而0V代表低电平的。对于RS232标准来说,它是个反逻辑,也叫做负逻辑。为何叫负逻辑?它的TXD和RXD的电压,-3V~-15V电压代表是1,+3~+15V电压代表是0。低电平代表的是1,而高电平代表的是0,所以称之为负逻辑。因此电脑的9针RS232串口是不能和单片机直接连接的,需要用一个电平转换芯片MAX232来完成

这个芯片就可以实现把标准RS232串口电平转换成我们单片机能够识别和承受的UART0V/5V电平。从这里大家似乎慢慢有点明白了,其实RS232串口和UART串口,它们的协议类型是一样的,只是电平标准不同而已,而MAX232这个芯片起到的就是中间人的作用,它把UART电平转换成RS232电平,也把RS232电平转换成UART电平,从而实现标准RS232接口和单片机UART之间的通信连接。

读取意外错误包数据的软件_意外的数据包读取错误_读取错误数据或已损坏

USB转串口通信

随着技术的发展,工业上还有RS232串口通信的大量使用,但是商业技术的应用上,已经慢慢的使用USB转UART技术取代了RS232串口,绝大多数笔记本电脑已经没有串口这个东西了,那我们要实现单片机和电脑之间的通信该怎么办呢?

们只需要在电路上添加一个USB转串口芯片,就可以成功实现USB通信协议和标准UART串行通信协议的转换,在我们的开发板上,我们使用的是CH340T这个芯片

我们需要用跳线帽把中间和下边的针短接在一起。右侧的CH340T这个电路很简单,把电源、晶振接好后,6脚和7脚的DP和DM分别接USB口的2个数据引脚上去,3脚和4脚通过跳线接到了我们单片机的TXD和RXD上去。

CH340T的电路里3脚位置加了个4148的二极管,是一个小技巧。因为这个单片机下载程序时需要冷启动,就是先点下载后上电,上电瞬间单片机会先检测需要不需要下载程序。虽然单片机的VCC是由开关来控制,但是由于CH340T的3脚是输出引脚,如果没有此二极管,开关后级单片机在断电的情况下,CH340T的3脚和单片机的P3.0(即RXD)引脚连在一起,有电流会通过这个引脚流入后级电路并且给后级的电容充电,造成后级有一定幅度的电压,这个电压值虽然只有两三伏左右,但是可能会影响到正常的冷启动。加了二极管后,一方面不影响通信,另外一个方面还可以消除这种不良影响。这个地方可以暂时作为了解,大家如果自己做这类电路,可以参考一下。

IO口模拟UART串口通信

UART串口波特率,常用的值是300、600、1200、2400、4800、9600、14400、19200、28800、38400、57600、115200等速率。IO口模拟UART串行通信程序是一个简单的演示程序,我们使用串口调试助手下发一个数据,数据加1后,再自动返回。

串口调试助手,这里我们直接使用STC-ISP软件自带的串口调试助手,先把串口调试助手的使用给大家说一下,如图11-6所示。第一步要选择串口助手菜单,第二步选择十六进制显示,第三步选择十六进制发送,第四步选择COM口,这个COM口要和自己电脑设备管理器里的那个COM口一致,波特率按我们程序设定好的选择,我们程序中让一个数据位持续时间是1/9600秒,那这个地方选择波特率就是选9600,校验位选N,数据位8,停止位1。

串口调试助手的实质就是利用电脑上的UART通信接口,发送数据给我们的单片机,也可以把我们的单片机发送的数据接收到这个调试助手界面上。

因为初次接触通信方面的技术,所以我把后面的IO模拟串口通信程序进行一下解释,大家可以边看我的解释边看程序,把底层原理先彻底弄懂。

变量定义部分就不用说了,直接看main主函数。首先是对通信的波特率的设定,在这里我们配置的波特率是9600,那么串口调试助手也得是9600。配置波特率的时候,我们用的是定时器T0的模式2。模式2中,不再是TH0代表高8位,TL0代表低8位了,而只有TL0在进行计数,当TL0溢出后,不仅仅会让TF0变1,而且还会将TH0中的内容重新自动装到TL0中。这样有一个好处,就是我们可以把想要的定时器初值提前存在TH0中,当TL0溢出后,TH0自动把初值就重新送入TL0了,全自动的,不需要程序中再给TL0重新赋值了,配置方式很简单,大家可以自己看下程序并且计算一下初值。

波特率设置好以后,打开中断,然后等待接收串口调试助手下发的数据。接收数据的时候,首先要进行低电平检测while(PIN_RXD),若没有低电平则说明没有数据,一旦检测到低电平,就进入启动接收函数()。接收函数最开始启动半个波特率周期,初学可能这里不是很明白。大家回头看一下我们的图11-2里边的串口数据示意图,如果在数据位电平变化的时候去读取,因为时序上的误差以及信号稳定性的问题很容易读错数据,所以我们希望在信号最稳定的时候去读数据。除了信号变化的那个沿的位置外,其它位置都很稳定,那么我们现在就约定在信号中间位置去读取电平状态,这样能够保证我们读的一定是正确的。

一旦读到了起始信号,我们就把当前状态设定成接收状态,并且打开定时器中断,第一次是半个周期进入中断后,对起始位进行二次判断一下,确认一下起始位是低电平,而不是一个干扰信号。以后每经过1/9600秒进入一次中断,并且把这个引脚的状态读到RxdBuf里边。等待接收完毕之后,我们再把这个RxdBuf加1,再通过TXD引脚发送出去,同样需要先发一位起始位,然后发8个数据位,再发结束位,发送完毕后,程序运行到while(PIN_RXD),等待第二轮信号接收的开始。

uart模块介绍

IO口模拟串口通信,让大家了解了串口通信的本质,但是我们的单片机程序却需要不停的检测扫描单片机IO口收到的数据,大量占用了单片机的运行时间。这时候就会有聪明人想了,其实我们并不是很关心通信的过程,我们只需要一个通信的结果,最终得到接收到的数据就行了。这样我们可以在单片机内部做一个硬件模块,让它自动接收数据,接收完了,通知我们一下就可以了,我们的51单片机内部就存在这样一个UART模块,要正确使用它,当然还得先把对应的特殊功能寄存器配置好。

51单片机的UART串口的结构由串行口控制寄存器SCON、发送和接收电路三部分构成,先来了解一下串口控制寄存器SCON。

SCON串行控制器的位分配(地址:0x98)

位:符号:复位值: 0:RI:0;1:TI:0;2:RB8:0;3:TB8:0;4:REN:0;5:SM2:0;6:SM1:0;7:SM0:0;

0位RI:接收中断标志位,当接收电路接收到停止位的中间位置时,RI由硬件置1,必须通过软件清零

1位TI:发送中断标志位,当发送电路发送到停止位的中间位置时,TI由硬件置1,必须通过软件清零。

2位RB8:模式2和3中接收到的第9位数据(很少用),模式1用来接收停止位。

3位TB8:模式2和3中要发送的第9位数据(很少用)。

4位REN:使能串行接收。由软件置位使能接收,软件清零则禁止接收。

5位SM2:多机通信控制位(极少用),模式1直接清零。

6位SM1和7位SM0:

这两位共同决定了串口通信的模式0~模式3共4种模式。我们最常用的就是模式1,也就是SM0=0,SM1=1,下边我们重点就讲模式1,其它模式从略。

对于串口的四种模式,模式1是最常用的,就是我们前边提到的1位起始位,8位数据位和1位停止位。下面我们就详细介绍模式1的工作细节和使用方法,至于其它3种模式与此也是大同小异,真正遇到需要使用的时候大家再去查阅相关资料就行了。

在我们使用IO口模拟串口通信的时候,串口的波特率是使用定时器T0的中断体现出来的。在硬件串口模块中,有一个专门的波特率发生器用来控制发送和接收数据的速度。对于单片机来讲,这个波特率发生器只能由定时器T1或定时器T2产生,而不能由定时器T0产生,这和我们模拟的通信是完全不同的概念。

如果用定时器2,需要配置额外的寄存器,默认是使用定时器1的,我们本章内容主要就使用定时器T1作为波特率发生器来讲解,方式1下的波特率发生器必须使用定时器T1的模式2,也就是自动重装载模式,定时器的重载值计算公式为:

TH1 = TL1 = 256 - 晶振值/12 /2/16 /波特率

和波特率有关的还有一个寄存器,是一个电源管理寄存器PCON,他的最高位可以把波特率提高一倍,也就是如果写PCON |= 0x80以后,计算公式就成了:

TH1 = TL1 = 256 - 晶振值/12 /16 /波特率

公式中数字的含义这里解释一下,256是8位定时器的溢出值,也就是TL1的溢出值,晶振值在我们的开发板上就是,12是说1个机器周期等于12个时钟周期,值得关注的是这个16,我们来重点说明。在IO口模拟串口通信接收数据的时候,采集的是这一位数据的中间位置,而实际上串口模块比我们模拟的要复杂和精确一些。他采取的方式是把一位信号采集16次,其中第7、8、9次取出来,这三次中其中两次如果是高电平,那么就认定这一位数据是1,如果两次是低电平,那么就认定这一位是0,这样一旦受到意外干扰读错一次数据,也依然可以保证最终数据的正确性。

串口通信的发送和接收电路在物理上有2个名字相同的SBUF寄存器,它们的地址也都是0x99,但是一个用来做发送缓冲,一个用来做接收缓冲。意思就是说,有2个房间,两个房间的门牌号是一样的,其中一个只出人不进人,另外一个只进人不出人,这样的话,我们就可以实现UART的全双工通信,相互之间不会产生干扰。但是在逻辑上呢,我们每次只操作SBUF,单片机会自动根据对它执行的是“读”还是“写”操作来选择是接收SBUF还是发送SBUF,后边通过程序,我们就会彻底了解这个问题。

UART串口程序:

一般情况下,我们编写串口通信程序的基本步骤如下所示:

1、配置串口为模式1。

2、配置定时器T1为模式2,即自动重装模式。

3、根据波特率计算TH1和TL1的初值,如果有需要可以使用PCON进行波特率加倍。

4、打开定时器控制寄存器TR1,让定时器跑起来。

这里还要特别注意一下,就是在使用T1做波特率发生器的时候,千万不要再使能T1的中断了。

我们先来看一下由IO口模拟串口通信直接改为使用硬件UART模块时的程序代码,看看程序是不是简单了很多,因为大部分的工作硬件模块都替我们做了。程序功能和IO口模拟的是完全一样的。

读取意外错误包数据的软件_读取错误数据或已损坏_意外的数据包读取错误

通信实例与ASCLL码

先抛开我们使用的汉字不谈,那么我们常用的字符就包含了0~9的数字、A~Z/a~z的字母、还有各种标点符号等。那么在单片机系统里面我们怎么来表示它们呢?ASCII码(hange,即美国信息互换标准代码)可以完成这个使命:我们知道,在单片机中一个字节的数据可以有0~255共256个值,我们取其中的0~127共128个值赋予了它另外一层涵义

我们用字符格式发送一个小写的a,返回一个十六进制的0x61,数码管上显示的也是61,ASCII码表里字符a对应十进制是97,等于十六进制的0x61;我们再用字符格式发送一个数字1,返回一个十六进制的0x31,数码管上显示的也是31,ASCII表里字符1对应的十进制是49,等于十六进制的0x31。这下大家就该清楚了:所谓的十六进制发送和十六进制接收,都是按字节数据的真实值进行的;而字符格式发送和字符格式接收,是按ASCII码表中字符形式进行的,但它实际上最终传输的还是一个字节数据。这个表格,当然不需要大家去记住,理解它,用的时候过来查就行了。

51单片机串口通信实例(字符串接收和发送)

#include《reg52.h》

//------------------串口通信协议-----------------//

/*

客户端数据包格式解释(长度恒为15):

例如:#

A--------数据包的开始标记(可以为A到Z,意味着数据包可以有26种)

01-----设备代号

--------指令(长度恒为10),指令的前4个人字符是指令头部,指令的后6个字符是指令尾部

#---------数据包的结束标记

服务器端数据包格式解释(长度恒为15):

例如:#

A--------数据包的开始标记(可以为A到Z,意味着数据包可以有26种)

02-----设备代号

--------指令(长度恒为10),指令的前4个人字符是指令头部,指令的后6个字符是指令尾部

#---------数据包的结束标记

*/

char [16]; //定义数据包长度为15个字符

#define ‘0’ //用于串口通信时,定义本地设备ID的第1位

#define ‘2’ //用于串口通信时,定义本地设备ID的第2位

#define ‘A’ //用于串口通信时,定义数据包头部的验证标记

char [16]={,,,‘_’,‘S’,‘e’,‘n’,‘T’,‘X’,‘X’,‘X’,‘X’,‘X’,‘X’,‘#’};

char [16]={,,,‘_’,‘B’,‘e’,‘a’,‘t’,‘X’,‘X’,‘X’,‘X’,‘X’,‘X’,‘#’};

//----------------------------------------------//

/*******************************

串口通信

MCU:89C52RC 11.0592MHz

//11.0592MHz 0xd0 1200bps

//12MHz 0xcc 1200bps

//11.0592MHz 0xfa 9600bps

//0xf4 11.0592MHz 0xf3 12MHz 4800bps

//均在SMOD=1的情况下(波特率倍增模式)

*******************************/

//串口发送函数

void ( char *TXStr)

ES=0;

while(*TXStr!=0)

SBUF=*TXStr;

while(TI==0);

TI=0;

TXStr++;

ES=1;

//串口接收函数

bit ()

char * RecStr=;

char num=0;

char count=0;

loop:

*RecStr=SBUF;

count=0;

RI=0;

if(num《14) //数据包长度为15个字符,尝试连续接收15个字符

num++;

RecStr++;

while(!RI)

count++;

if(count》130)return 0; //接收数据等待延迟,等待时间太久会导致CPU运算闲置,太短会出现“数据包被分割”,默认count=130

goto loop;

return 1;

//定时器1用作波特率发生器

void ()

SCON=0x50; //串口方式1,使能接收

TMOD|=0x20; //定时器1工作方式2(8位自动重装初值)

TMOD&=~0x10;

TH1=0xfa; //9600bps

TL1=0xfa;

PCON|=0x80; //SMOD=1

TR1=1;

TI=0;

RI=0;

//PS=1; //提高串口中断优先级

ES=1; //开启串口中断使能

//比较指令头部

bit (char [])

char CharNum;

for(CharNum=0;CharNum《4;CharNum++) //指令长度为10个字符

if(!([CharNum+4]==[CharNum]))

return 0; //指令头部匹配失败

return 1; //指令头部匹配成功

//比较指令尾部(start:从哪里开始比较,quality:比较多少个字符,[]:要比较的字符串)

bit ( char start, char quality,char [])

char CharNum;

for(CharNum=0;CharNum《quality;CharNum++)

if(!([start+CharNum]==[CharNum]))

return 0;

return 1;

bit () //处理串口接收数据包函数(成功处理数据包则返回1,否则返回0)

//();

if([0]==&&[14]==‘#’) //进行数据包头尾标记验证

switch([1]) //识别发送者设备ID的第1位数字

case ‘0’:

switch([2]) //识别发送者设备ID的第2位数字

case ‘3’:

if((“Ligt”)) //判断指令头部是否为“Ligt”

//下面是指令尾部分析

switch([8])

case ‘0’:

switch([9])

case ‘0’:

return 0;

case ‘1’:

if((10,3,“Off”)) //#

//要执行的代码

return 1;

if((10,3,“On_”))

return 1;

return 0;

default:

return 0;

case ‘1’:

default:

return 0;

if((“SenT”))

if((“jdq_”))

if((“Try!”))

return 0;

default:

return 0;

default:

return 0;

return 0;

/************************

中断函数

************************/

//串口中断服务函数-----------

void USART() 4 //标志位TI和RI需要手动复位,TI和RI置位共用一个中断入口

if(())

//数据包长度正确则执行以下代码

();

else

//数据包长度错误则执行以下代码

//LED1=~LED1;

RI=0; //接收并处理一次数据后把接收中断标志清除一下,拒绝响应在中断接收忙的时候发来的请求

/***************************

主函数

***************************/

void main()

EA=1;

();

while(1)

//();//空格20H,回车0DH