eg1:数码管如何显示出字符
51单片机40个引脚的功能需要记住**
- RXD:表示的是串行输入口
- INT0:外部中断0
- INT1:外部中断1
- TO : 外部中断0
- T1 :外部中断1
- WR: 外部输入存储器写
- RD: 外部输出存储器读
- XTK2/XTL1 单片机晶振的输入端
- VSS == GND
- ALE 可以输出六分之一的时钟方波
eg2:数码管的静态显示
在单片机系统中,常用的显示器有以下几种:数码管的显示通常是由锁存器来进行控制的
- LCD(液晶显示器):LCD是一种常见的显示器类型,它使用液晶技术来显示图像和字符。LCD显示器可以以字符、图形或者图像的形式显示信息,通常具有较低的功耗和较高的分辨率。LCD显示器通常需要使用驱动芯片来控制显示内容。
- LED(发光二极管显示器):LED显示器使用发光二极管来显示字符、数字或者图像。它具有高亮度、低功耗和长寿命等优点。LED显示器可以分为七段LED和点阵LED两种类型,七段LED可以显示数字和部分字母,而点阵LED可以显示更复杂的图像和字符。
- OLED(有机发光二极管显示器):OLED是一种高对比度、高亮度、快速响应和广视角的显示技术。OLED显示器由许多有机发光材料组成,可以直接发射光线。OLED显示器具有较低的功耗和较薄的结构,适用于小型设备和便携式设备。
- VFD(真空荧光显示器):VFD显示器使用一种发光的热电子器件来显示字符和数字。它具有高亮度、广视角和长寿命等特点。VFD显示器通常用于需要高可见性和抗干扰能力的应用,如家电、汽车仪表盘等。
#include <REGX52.H>
#include <INTRINS.H>
//控制断点
sbit dula = P2^6;
sbit wela = P2^7;
//控制数码管的每一个位置的数字
sbit mun1 = P0^0;
sbit mun2 = P0^1;
sbit mun3 = P0^2;
sbit mun4 = P0^3;
/*
共阳数码管码表
0xc0,//0
0xf9,//1
0xa4,//2
0xb0,//3
0x99,//4
0x92,//5
0x82,//6
0xf8,//7
0x80,//8
0x90,//9
0x88,//A
0x83,//B
0xc6,//C
0xa1,//D
0x86,//E
0x8e, //F
0x8c, //P
0xc1,//U
0x91,//Y
0x7c,//L
0x00,//全亮
0xff //熄灭
数码管码表
0x3F, //"0"
0x06, //"1"
0x5B, //"2"
0x4F, //"3"
0x66, //"4"
0x6D, //"5"
0x7D, //"6"
0x07, //"7"
0x7F, //"8"
0x6F, //"9"
0x77, //"A"
0x7C, //"B"
0x39, //"C"
0x5E, //"D"
0x79, //"E"
0x71, //"F"
0x76, //"H"
0x38, //"L"
0x37, //"n"
0x3E, //"u"
0x73, //"P"
0x5C, //"o"
0x40, //"-"
0x00 //熄灭
*/
void main(){
//位锁存器开启
wela = 1;
// 给p0口送数0011 1111---> 1111 1100 == fc
P0 = 0x00;
// 锁存器关闭
wela = 0;
// 断选锁存器
dula = 1;
P0 = 0x06;
dula = 0;
while(1);
}
数码管静态显示
#include <REGX52.H>
#include <INTRINS.H>
//控制断点
sbit dula = P2^6;
sbit wela = P2^7;
// 宏定义
#define uint unsigned int;
#define uchar unsigned char;
uint i,ret;
uchar num;
// 创建一个数组,编写code的目的就是将数据存放在程序存储器中,不写code会放在随机存储器当中
uchar code table[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x76,0x38,0x37,0x3E};
// 延时函数
void Delay1000ms(void) //@11.0592MHz
{
unsigned char data i, j, k;
_nop_();
_nop_();
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main(){
// 操作所有的数码管让数码管亮起
wela = 1;
P0 = 0xc0;
wela = 0;
while(1){
ret = sizeof(table)/sizeof(table[0]);
for(num = 0;num <= ret; num ++){
// 操作单个数码管让它分别显示数据
dula = 1;
P0 = table[num];
dula = 0;
Delay1000ms();
}
}
}
eg3:中断概念
- CPU在处理某一事件A时,突然发生了另一件事B请求CPU去迅速处理(中断发生)
- CPU暂时中断当前的工作,转去处理事件B(中断响应和中断服务)
- 待CPU将事件B处理完毕后,在回到原来的事件A被中断的地方继续处理事件A(中断返回),这一过程被称为中断。
80C51是一种经典的单片机系列,其中断系统结构如下:
- 中断源:80C51中断系统包含多种中断源,例如外部中断、定时器/计数器中断、串行通信中断等。这些中断源可以触发中断请求,引起中断处理。
- 中断向量表:80C51中断系统采用中断向量表来管理不同中断源的中断处理程序。中断向量表是一组存储中断处理程序地址的内存地址。每个中断源都有一个唯一的中断向量,当中断请求产生时,CPU会根据中断源的优先级选择相应的中断向量,跳转到对应的中断处理程序。
- 中断优先级和屏蔽:80C51中断系统支持多级中断优先级。不同中断源可以设置不同的优先级,高优先级的中断会优先处理。此外,中断系统还提供了可屏蔽中断的功能。通过设置中断屏蔽位,可以屏蔽或允许特定中断源的中断请求。
- 中断处理程序:中断处理程序是实际执行中断服务的代码。每个中断源都有一个对应的中断处理程序,当中断请求发生时,CPU会跳转到对应的中断处理程序开始执行。中断处理程序通常需要保存和恢复现场,处理中断事件,并在完成后返回到主程序。
- 中断返回:中断处理程序执行完成后,需要通过中断返回指令(如RET)返回到主程序继续执行。中断返回指令会恢复保存的现场,包括程序计数器等寄存器的值,并从栈中弹出返回地址。
80C51的中断系统结构提供了一种有效的处理异步事件的机制。通过合理配置中断源的优先级和中断处理程序的设计,可以实现对实时性要求较高的应用的响应和处理。
中断技术在计算机系统中具有以下优点:**
- 实时性:中断技术可以及时响应外部事件或者内部事件的发生,使得系统可以快速地对事件做出处理。这对于需要实时响应的应用非常重要,例如实时控制系统、数据采集系统等。
- 节约CPU资源:中断技术可以实现异步事件的处理,使得CPU可以在处理一个事件时,同时处理其他任务或者等待其他事件的发生。这样可以充分利用CPU资源,提高系统整体的效率。
- 灵活性:中断技术可以对不同类型的事件进行分类和处理,通过设置不同的中断源和中断处理程序,可以灵活地适应不同的应用需求。
- 可靠性:中断技术可以保证系统对事件的响应和处理不受主程序的影响,即使主程序出现问题或者阻塞,中断仍然可以正常工作,保证系统的可靠性。
- 外设扩展性:中断技术可以方便地与外部设备进行连接和交互。通过与外部设备的中断触发机制配合,可以实现对外部设备的高效管理和控制。
中断请求标志
80c51单片机的中断优先级原则
- CPU同时收到几个中断时,首先响应优先级别最高的中断请求
- 正在进行的中断过程不能被新的同级或者是低优先级的中断请求中断
- 正在请求 的低优先级中断服务,能被高优先级中断请求所中断
#include <REGX52.H>
#include <INTRINS.H>
//控制断点
sbit dula = P2^6;
sbit wela = P2^7;
sbit L1= P1^0;
// 宏定义
#define uint unsigned int;
#define uchar unsigned char;
uint i,ret;
uchar num;
// 创建一个数组,编写code的目的就是将数据存放在程序存储器中,不写code会放在随机存储器当中
uchar code table[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x76,0x38,0x37,0x3E};
// 延时函数
void Delay1000ms(void) //@11.0592MHz
{
unsigned char data i, j, k;
_nop_();
_nop_();
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
// 中断服务程序,编写中断函数时无返回值函数名,interrupt 加上中断序号
void exter0() interrupt 0{
L1 = 0;
}
void main(){
// 开总中断
EA = 1;
// 开外部中断0
EX0 = 1;
// 跳变触发中断的方式 TCON =0X01;
IT0 = 1;
// 操作所有的数码管让数码管亮起
wela = 1;
P0 = 0xc0;
wela = 0;
while(1){
ret = sizeof(table)/sizeof(table[0]);
for(num = 0;num <= ret; num ++){
// 操作单个数码管让它分别显示数据
L1 = 1;
dula = 1;
P0 = table[num];
dula = 0;
Delay1000ms();
}
}
}
eg4:单片机定时的应用**
80C51微控制器中的定时器和计数器是其内部的重要功能模块,用于计时、计数和生成定时中断等操作。以下是关于80C51定时器和计数器的基本介绍:
- 定时器和计数器功能:80C51微控制器中的定时器和计数器是16位的功能模块,可以用于计时和计数操作。定时器可以按照设定的时间间隔自动计时,而计数器可以按照外部触发信号进行计数。
- 定时器的工作方式:80C51的定时器可以以不同的方式工作,包括定时模式、计数模式和PWM输出模式等。在定时模式下,定时器可以自动地根据设定的定时器初值和工作模式进行计时,并在计时结束时触发定时中断。
- 计数器的工作方式:80C51的计数器可以通过外部的触发信号进行计数操作。当触发信号发生边沿或状态变化时,计数器会自动地对计数值进行增加或者减少,并在计数达到设定值时触发中断。
- 定时器/计数器的控制寄存器:80C51微控制器中的定时器和计数器具有一些控制和设置寄存器,用于配置和管理定时器/计数器的工作模式、计时间隔、计数模式等参数。通过对这些寄存器的设置,可以实现不同的定时和计数功能。
- 定时中断:80C51的定时器和计数器模块可以生成定时中断信号。当定时器计时或计数达到设定值时,会触发中断请求,通过中断向量来处理相应的中断服务程序。
定时器和计数器的工作原理如下:
- 定时器的工作原理:
- 定时器内部有一个基准时钟源,可以是外部晶振或者内部时钟源。这个时钟源会提供一个固定的时间间隔,例如每个时钟脉冲。
- 定时器内部有一个计数寄存器,用于存储定时器的计数值。这个计数值会随着时钟源的脉冲到来而递增。
- 定时器还有一个设定值寄存器,用于设置定时器的初值。当定时器的计数值达到设定值时,触发定时中断,并重新加载设定值,从而实现循环定时的功能。
- 在定时器工作期间,可以根据设定的工作模式,进行不同的操作,例如自动重新加载、停止计数、触发输出等。
- 计数器的工作原理:
- 计数器内部也有一个基准时钟源,可以是外部晶振或者内部时钟源。这个时钟源会提供一个固定的时钟脉冲或者触发信号。
- 计数器内部有一个计数寄存器,用于存储计数器的计数值。这个计数值会随着时钟源的脉冲或者触发信号的到来而递增或者递减。
- 计数器还有一个设定值寄存器,用于设置计数器的初值。当计数器的计数值达到设定值时,触发中断请求,并重新加载设定值,从而实现循环计数的功能。
- 在计数器工作期间,可以根据设定的工作模式,进行不同的操作,例如触发中断、输出触发信号等。
…
代码演示
#include <REGX52.H>
#include <INTRINS.H>
#define uint unsigned int
#define uchar unsigned char
sbit dula = P2^6;
sbit wela = P2^7;
uchar temp,aa,numwe,numdu,lenght1,lenght2;
uchar code table[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x76,0x38,0x37,0x3E};
uchar code tablewe[] = {0xfe,0xfd,0xf7,0xef,0xdf};
// 编写中断函数using 后面跟机,表示的是使用第几组的工作寄存器
void timer0() interrupt 1{
TH0 = (65536-50000)/256;// 高8位
TL0 = (65536-50000)/256; // 低8位
aa++;
}
void main(){
numdu = 0;
numwe = 0;
aa = 0;
// 选择寄存器的工作方式
TMOD = 0x01;
// 计算初值以2秒的时间变化
TH0 = (65536-50000)/2556;// 高8位
TL0 = (65536-50000)%256; // 低8位
// 中断方式,开启中断EA = 1
EA = 1;
// 开启定时器中断
ET0 = 1;
//TR0 = 1 启动定时器
TR0 = 1;
// 计算数组长度
lenght1 = sizeof(table)/sizeof(table[0]);
lenght2 = sizeof(tablewe)/sizeof(tablewe[0]);
while(1){
if(aa == 4){
aa = 0;
numdu++;
if(numdu == 10){
numdu = 1;
}
dula = 1;
P0= table[numdu];
dula = 0;
wela = 1;
P0 = tablewe[numwe];
wela = 0;
numwe++;
if(numwe == 6){
numwe = 0;
}
}
}
}
动态显示灯管
数码管的动态显示原理如下:
- 数码管的基本结构:
- 数码管由多个发光二极管(LED)组成,通常有7个或14个。
- 每个发光二极管都有一个独立的引脚用于控制,称为段选引脚。
- 数码管还有一个共阳或共阴的引脚,用于控制整个数码管的亮灭。
- 动态显示原理:
- 在动态显示中,每次只有一个数码管被点亮,而其他数码管则处于熄灭状态。
- 控制器通过快速切换每个数码管的段选引脚,使得人眼感知到所有数码管都在同时显示。
- 控制器在非常短的时间内依次控制每个数码管,每个数码管被点亮的时间很短,通常只有几毫秒。
- 控制器通过迅速切换数码管的段选引脚,可以使得数码管的亮度保持较为均匀,因为人眼对于光的持续时间较短的光亮感知能力较弱。
- 显示数据的存储与转换:
- 要在数码管上显示具体的数字或字符,需要将对应的显示数据转换为段选引脚的控制信号。
- 通常使用存储器、寄存器或者逻辑门电路来实现数据的存储和转换。
- 控制器将需要显示的数据存储在内部存储器或寄存器中,并根据需要将对应的控制信号输出到数码管的段选引脚,以控制每个发光二极管的亮灭。
通过快速切换数码管的段选引脚,控制器可以实现数码管的动态显示。通过控制显示数据的存储和转换,可以在数码管上显示各种数字、字符和符号。
#include <REGX52.H>
#include <INTRINS.H>
#define uint unsigned int
#define uchar unsigned char
sbit dula = P2^6;
sbit wela = P2^7;
uchar temp,aa,numwe,numdu,lenght1,lenght2;
uchar code table[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x76,0x38,0x37,0x3E};
uchar code tablewe[] = {0xfe,0xfd,0xf7,0xef,0xdf};
// 编写中断函数using 后面跟机,表示的是使用第几组的工作寄存器
void timer0() interrupt 1{
TH0 = (65536-50000)/256;// 高8位
TL0 = (65536-50000)/256; // 低8位
aa++;
}
void main(){
numdu = 0;
numwe = 0;
aa = 0;
// 选择寄存器的工作方式
TMOD = 0x01;
// 计算初值以2秒的时间变化
TH0 = (65536-50000)/2556;// 高8位
TL0 = (65536-50000)%256; // 低8位
// 中断方式,开启中断EA = 1
EA = 1;
// 开启定时器中断
ET0 = 1;
//TR0 = 1 启动定时器
TR0 = 1;
// 计算数组长度
lenght1 = sizeof(table)/sizeof(table[0]);
lenght2 = sizeof(tablewe)/sizeof(tablewe[0]);
while(1){
if(aa == 4){
aa = 0;
numdu++;
if(numdu == 10){
numdu = 1;
}
dula = 1;
P0= table[numdu];
dula = 0;
wela = 1;
P0 = tablewe[numwe];
wela = 0;
numwe++;
if(numwe == 6){
numwe = 0;
}
}
}
}
数码管动态显示
#include <REGX52.H>
#include <INTRINS.H>
#define uint unsigned int
#define uchar unsigned char
sbit dula = P2^6;
sbit wela = P2^7;
uchar temp,aa,numwe,numdu,lenght1,lenght2,shi,ge;
uchar code table[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
//延迟5000ms
void Delay5000ms(void) //@11.0592MHz
{
unsigned char data i, j, k;
_nop_();
_nop_();
i = 211;
j = 30;
k = 11;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main(){
temp = 12;
numdu = 0;
while(1){
shi = temp/10;
ge = temp%10;
dula = 1;
P0 = table[shi];
dula = 0;
wela = 1;
P0 = 0xfe;
wela = 0;
Delay5000ms();
dula = 1;
P0 = table[ge];
dula = 0;
wela = 1;
P0 = 0xfd;
wela = 0;
Delay5000ms();
}
}
以上代码的显示结果为三个数轮流在不同位数显示
一下代码的结果为三个数同时显示在数码管上
#include <REGX52.H>
#include <INTRINS.H>
#define uint unsigned int
#define uchar unsigned char
sbit dula = P2^6;
sbit wela = P2^7;
uchar temp,aa,numwe,numdu,bai,shi,ge;
uchar code table[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
//延迟5000ms
void delay(uint z){
uint x,y;
for(x = z; x > 0; x --){
for(y = 110; y > 0; y--){
}
}
}
void main(){
temp = 152;
numdu = 0;
while(1){
bai = temp/100;
shi = temp%100/10;
ge = temp%10;
dula = 1;
P0 = table[bai];
dula = 0;
wela = 1;
P0 = 0xfe;
wela = 0;
delay(5);
dula = 1;
P0 = table[shi];
dula = 0;
wela = 1;
P0 = 0xfd;
wela = 0;
delay(5);
dula = 1;
P0 = table[ge];
dula = 0;
wela = 1;
P0 = 0xfb;
wela = 0;
delay(5);
}
}
编写子程序灵活调用
#include <REGX52.H>
#include <INTRINS.H>
#define uint unsigned int
#define uchar unsigned char
sbit dula = P2^6;
sbit wela = P2^7;
uchar temp,aa,numwe,numdu,bai,shi,ge;
uchar code table[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
//延迟5000ms
void delay(uint z){
uint x,y;
for(x = z; x > 0; x --){
for(y = 110; y > 0; y--){
}
}
}
void display(uchar bai,uchar shi,uchar ge)
{
dula = 1;
P0 = table[bai];
dula = 0;
wela = 1;
P0 = 0xfe;
wela = 0;
delay(5);
dula = 1;
P0 = table[shi];
dula = 0;
wela = 1;
P0 = 0xfd;
wela = 0;
delay(5);
dula = 1;
P0 = table[ge];
dula = 0;
wela = 1;
P0 = 0xfb;
wela = 0;
delay(5);
}
void main(){
temp = 152;
numdu = 0;
bai = temp/100;
shi = temp%100/10;
ge = temp%10;
while(1){
display(bai,shi,ge);
}
}
定时器中断三位数准备增加
#include <REGX52.H>
#include <INTRINS.H>
#define uint unsigned int
#define uchar unsigned char
sbit dula = P2^6;
sbit wela = P2^7;
uchar temp,aa,bai,shi,ge;
uchar code table[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
// 初始化函数
void init(){
wela = 0;
dula = 0;
temp = 0;
// 初始化定时器
TMOD = 0x01;
// 定时器模式设置定时器初始值
TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256;
//开始中断
EA = 1;
ET0 = 1;
TR0 = 1;
}
//延迟5000ms
void delay(uint z){
uint x,y;
for(x = z; x > 0; x --){
for(y = 110; y > 0; y--){
}
}
}
// 编写中断函数using 后面跟机,表示的是使用第几组的工作寄存器
void timer0() interrupt 1{
TH0 = (65536-50000)/256;// 高8位
TL0 = (65536-50000)/256; // 低8位
aa++;
}
void display(uchar bai,uchar shi,uchar ge)
{
dula = 1;
P0 = table[bai]; // 送百位数
dula = 0; // 消隐
P0 = 0xff;
wela = 1;
P0 = 0xfe; // 位选通百位数
wela = 0;
delay(5);
dula = 1;
P0 = table[shi];
dula = 0;
P0 = 0xff;
wela = 1;
P0 = 0xfd;
wela = 0;
delay(5);
dula = 1;
P0 = table[ge];
dula = 0;
P0 = 0xff;
wela = 1;
P0 = 0xfb;
wela = 0;
delay(5);
}
void main(){
// 调用初始化函数
init();
while(1){
if(aa == 20){
aa = 0;
temp ++;
if(temp == 100){
temp = 0;
}else{
bai = temp /100;
shi = temp %100/10;
ge = temp%10;
}
}
display(bai,shi,ge);
}
}
实现的效果为从后往前数字自增1
eg:51单片机较为重要的部分为,中断系统,定时器和串口需要重点掌握,important