初识51单片机
我使用的是开拓者提供的51单片机,资料打包如下:
开拓者V2光盘资料 提取码: 85nk
STC89C51RC/RD+系列单片机简介
STC89C51RC/RD+系列单片机(包括STC89C52RC)是宏晶科技推出的新一代超强抗干扰、高速、低功耗的单片机,与传统8051系列单片机的指令和引脚完全兼容。12时钟/机器周期和6时钟/机器周期可任意选择。
命名规则
主要特性
引脚封装
产品选型表
开发板实物图
LED灯相关
LED简介
LED介绍
LED即发光二极管,它是一种能将电能转化为光能的半导体电子元件。
普通小功率LED电压范围:1.8-2.4V,电流为:20mA
如何点亮LED
LED具有单向导通性,只能往一个方向导通。正极→负极
LED模块电路
编写程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
#include "reg52.h" typedef unsigned int u16; typedef unsigned char u8;
sbit led1=P2^0; sbit led2=P2^1; sbit led3=P2^2; sbit led4=P2^3; sbit led5=P2^4; sbit led6=P2^5; sbit led7=P2^6; sbit led8=P2^7;
void delay(u16 i) { while(i--); }
void main() { while(1) { led1=0,led4=0,led7=0,led8=0; delay(50000); led1=1,led4=1,led7=1,led8=1; delay(50000); led2=0,led5=0; delay(50000); led2=1,led5=1; delay(50000); led3=0,led6=0; delay(50000); led3=1,led6=1; delay(50000); led1=0,led2=0,led3=0; delay(50000); led1=1,led2=1,led3=1; delay(50000); led4=0,led5=0,led6=0; delay(50000); led4=1,led5=1,led6=1; delay(50000); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
#include "reg52.h" #include <intrins.h>
typedef unsigned int u16; typedef unsigned char u8;
#define LED P2
void delay(u16 i) { while(i--); }
void main() { u8 i; LED=0xfe; delay(50000); while(1) { #if 1 LED=0xfe; for(i=0;i<8;i++) { LED=~(~0xfe<<i); delay(50000); } #endif
#if 0 for(i=0;i<7;i++) { LED=_crol_(LED,1); delay(50000); } for(i=0;i<7;i++) { LED=_cror_(LED,1); delay(50000); } #endif } }
|
蜂鸣器报警
蜂鸣器简介
蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器两种类型。
(1)压电式蜂鸣器主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。多谐振荡器由晶体管或集成电路构成,当接通电源后(1.5~15V直流工作电压),多谐振荡器起振,输出1.5~5kHZ的音频信号,阻抗匹配器推动压电蜂鸣片发声。
(2)电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场,振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。
如何调节蜂鸣器发声音色及声音大小?
(1)改变单片机引脚输出波形的频率,就可以调整控制蜂鸣器音调,产生各种不同音色、音调的声音。
(2)改变输出的高低电平占空比,则可以控制蜂鸣器的声音大小。
蜂鸣器模块电路
编写程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
#include "reg52.h" #include <intrins.h>
typedef unsigned int u16; typedef unsigned char u8;
sbit beep=P1^5;
void delay(u16 i) { while(i--); }
void main() { while(1) { beep=~beep; delay(50); } }
|
数码管相关–74HC245
数码管简介
数码管是一种半导体发光器件,其基本单元是发光二极管。数码管也称为LED数码管,是由多个发光二极管封装在一起组成“8”字型的器件,引线已在内部连接完成,只需引出它们的各个笔划,公共电极。
LED数码管根据LED的不同接法可以分为2类:共阴数码管和共阳数码管。
如下图(b),左为共阴数码管,右为共阳数码管。
共阴数码管码表
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d,
0 1 2 3 4 5
0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c,
6 7 8 9 A B
0x39, 0x5e, 0x79, 0x71, 0x00,
C D E F 无显示
共阳数码管码表
0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92,
0 1 2 3 4 5
0x82, 0xF8, 0x80, 0x90, 0x88, 0x83,
6 7 8 9 A B
0xC6, 0xA1, 0x86, 0x8E, 0xFF,
C D E F 无显示
数码管模块电路
程序编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
sbit LSA=P3^0; sbit LSB=P3^1; sbit LSC=P3^3;
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(u16 i) { while(i--); }
void main() { LSA=0; LSB=0; LSC=0; P0=smgduan[2]; delay(50000); LSA=1; LSB=0; LSC=0; P0=smgduan[0]; delay(50000); LSA=0; LSB=1; LSC=0; P0=smgduan[0]; delay(50000); LSA=1; LSB=1; LSC=0; P0=smgduan[1]; delay(50000); LSA=0; LSB=0; LSC=1; P0=smgduan[0]; delay(50000); LSA=1; LSB=0; LSC=1; P0=smgduan[7]; delay(50000); LSA=0; LSB=1; LSC=1; P0=smgduan[2]; delay(50000); LSA=1; LSB=1; LSC=1; P0=smgduan[5]; delay(50000); LSA=0; LSB=0; LSC=1; P0=smgduan[2]; delay(50000); LSA=1; LSB=0; LSC=1; P0=smgduan[0]; delay(50000); LSA=0; LSB=1; LSC=1; P0=smgduan[0]; delay(50000); LSA=1; LSB=1; LSC=1; P0=smgduan[1]; delay(50000); LSA=0; LSB=0; LSC=0; P0=smgduan[0]; delay(50000); LSA=1; LSB=0; LSC=0; P0=smgduan[7]; delay(50000); LSA=0; LSB=1; LSC=0; P0=smgduan[2]; delay(50000); LSA=1; LSB=1; LSC=0; P0=smgduan[5]; delay(50000); while(1);
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
sbit LSA=P3^0; sbit LSB=P3^1; sbit LSC=P3^3;
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(u16 i) { while(i--); }
void DigDisplay() { u8 i; for(i=0;i<8;i++) { switch(i) { case(0): LSA=0;LSB=0;LSC=0; break; case(1): LSA=1;LSB=0;LSC=0; break; case(2): LSA=0;LSB=1;LSC=0; break; case(3): LSA=1;LSB=1;LSC=0; break; case(4): LSA=0;LSB=0;LSC=1; break; case(5): LSA=1;LSB=0;LSC=1; break; case(6): LSA=0;LSB=1;LSC=1; break; case(7): LSA=1;LSB=1;LSC=1; break; } P0=smgduan[i]; delay(100); P0=0x00; } }
void main() { while(1) { DigDisplay(); } }
|
独立按键
按键简介
按键是一种电子开关,使用时轻轻按下开关按钮就可使开关接
通,当松开手时,开关断开。
通常的按键所用开关为机械弹性开关,当机械触点断开 、闭合
时,电压信号如下:
独立按键模块电路
程序编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
sbit k1=P1^4; sbit k2=P1^6; sbit k3=P3^2; sbit k4=P1^7;
sbit led1=P2^0; sbit led2=P2^1; sbit led3=P2^2; sbit led4=P2^3;
void delay(u16 i) { while(i--); }
void keypros() { if(k1==0) { delay(1000); if(k1==0) { led1=~led1; } while(!k1); } if(k2==0) { delay(1000); if(k2==0) { led2=~led2; } while(!k2); } if(k3==0) { delay(1000); if(k3==0) { led3=~led3; } while(!k3); } if(k4==0) { delay(1000); if(k4==0) { led4=~led4; } while(!k4); } }
void main() { while(1) { keypros(); } }
|
矩阵按键(4X4)
4X4矩阵按键简介
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键
排列成矩阵形式。在矩阵式键盘中,每条水平线和垂直线在交叉处
不直接连通,而是通过一个按键加以连接。
矩阵按键识别方法:
(1)逐行扫描
可以通过高四位轮流输出低电平来对矩阵键盘进行逐行
扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,
然后通过接收到的数据是哪一位为0来判断是哪一个按键被按下。
(2)行列扫描
可以通过高四位全部输出低电平,低四位输出高电平。当接收到的数据,低四位
不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一列有按键
按下,然后再反过来,高四位输出高电平,低四位输出低电平,然后根据接收到的高四位的
值判断是那一行有按键按下,这样就能够确定是哪一个按键按下了。
4X4矩阵按键模块电路
编写程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
#define GPIO_DIG P0 #define GPIO_KEY P1
sbit LSA=P3^0; sbit LSB=P3^1; sbit LSC=P3^3;
u8 KeyValue;
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(u16 i) { while(i--); }
void KEY_Scan(void) { char a=0; GPIO_KEY=0x0f; if(GPIO_KEY!=0x0f) { delay(1000); if(GPIO_KEY!=0x0f) { GPIO_KEY=0X0F; switch(GPIO_KEY) { case(0X07): KeyValue=0;break; case(0X0b): KeyValue=1;break; case(0X0d): KeyValue=2;break; case(0X0e): KeyValue=3;break; } GPIO_KEY=0XF0; switch(GPIO_KEY) { case(0X70): KeyValue=KeyValue;break; case(0Xb0): KeyValue=KeyValue+4;break; case(0Xd0): KeyValue=KeyValue+8;break; case(0Xe0): KeyValue=KeyValue+12;break; } while((a<50)&&(GPIO_KEY!=0xf0)) { delay(1000); a++; } } } }
void main() { LSA=0; LSB=0; LSC=0; while(1) { KEY_Scan(); GPIO_DIG=smgduan[KeyValue]; } }
|
点阵(8X8)–74HC595
8X8LED点阵简介
LED点阵是由发光二极管排列组成的显示器件,在我们日常生活的电器中随处可见,被广泛应用于汽车报站器,广告屏等。
8*8LED点阵内部结构:
8X8LED点阵模块电路
编写程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
|
#include "reg51.h" #include <intrins.h>
typedef unsigned int u16; typedef unsigned char u8;
sbit SRCLK=P3^6; sbit RCLK=P3^5; sbit SER=P3^4;
void HC595SendByte(u8 dat) { u8 a; SRCLK=0; RCLK=0; for(a=0;a<8;a++) { SER=dat>>7; dat<<=1;
SRCLK=1; _nop_(); _nop_(); SRCLK=0; }
RCLK=1; _nop_(); _nop_(); RCLK=0; }
void main() { while(1) { HC595SendByte(0x80); P0=0x7f; delay(50000); HC595SendByte(0XC0); P0=0X3f; delay(50000); HC595SendByte(0XE0); P0=0X1f; delay(50000); HC595SendByte(0XF0); P0=0X0f; delay(50000); HC595SendByte(0XF8); P0=0X07; delay(50000); HC595SendByte(0XFC); P0=0X03; delay(50000); HC595SendByte(0XFE); P0=0X01; delay(50000); HC595SendByte(0XFF); P0=0X00; delay(50000); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
|
#include "reg51.h" #include <intrins.h>
typedef unsigned int u16; typedef unsigned char u8;
sbit SRCLK=P3^6; sbit RCLK=P3^5; sbit SER=P3^4;
u8 ledduan0[]={0X00,0X00,0X3E,0X41,0X41,0X41,0X3E,0X00}; u8 ledduan1[]={0X00,0X00,0X24,0X44,0XFC,0X04,0X04,0X00}; u8 ledwei[]={0X7f,0Xbf,0Xdf,0Xef,0Xf7,0Xfb,0Xfd,0Xfe};
void delay(u16 i) { while(i--); }
void HC595SendByte(u8 dat) { u8 a; SRCLK=0; RCLK=0; for(a=0;a<8;a++) { SER=dat>>7; dat<<=1;
SRCLK=1; _nop_(); _nop_(); SRCLK=0; }
RCLK=1; _nop_(); _nop_(); RCLK=0; }
void main() { u8 i,j; while(1) { P0=0x7f; for(i=0;i<8;i++) { P0=ledwei[i]; HC595SendByte(ledduan0[i]); delay(100); HC595SendByte(0X00); }
} }
|
直流电机控制–TC1508S
直流电机简介
直流电机是指能将直流电能转换成机械能的旋转电机。
相关参数:
轴长:8mm
轴径:2mm
电压:1-6v
参考电流:0.35-0.4A
3v转速:17000-18000转每分钟
直流电机驱动模块电路
编写程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
#include "reg51.h" #include <intrins.h>
typedef unsigned int u16; typedef unsigned char u8;
sbit motoa=P1^0; sbit motob=P1^1; sbit k1=P3^0;
u8 mode=0;
void delay(u16 i) { while(i--); }
void main() { while(1) { if(k1==0) { delay(1000); if(k1==0) { mode++; if(mode==2)mode=0; } while(!k1); } if(mode==0) { motoa=0; motob=0; } else if(mode==1) { motoa=0; motob=1; } } }
|
中断系统
中断简介
中断技术不仅解决了快速主机与慢速I/O设备的数据传送问题,而且还具有如下优点:
①分时操作。CPU可以分时为多个I/O设备服务,提高了计算机的利用率;
②实时响应。CPU能够及时处理应用系统的随机事件,系统的实时性大大增强;
③可靠性高。CPU具有处理设备故障及掉电等突发性事件能力,从而使系统可靠性提高。
中断系统结构
89C51的中断系统有5个中断源 ,2个优先级,可实现二级中断嵌套。
①INT0(P3.2),可由IT0(TCON.0)选择其为低电平有效还是下降沿有效。当CPU检测
到P3.2引脚上出现有效的中断信号时,中断标志IE0(TCON.1)置1,向CPU申请中断。
②INT1(P3.3),可由IT1(TCON.2)选择其为低电平有效还是下降沿有效。当CPU检测
到P3.3引脚上出现有效的中断信号时,中断标志IE1(TCON.3)置1,向CPU申请中断。
③T0(P3.4),TF0(TCON.5),片内定时/计数器T0溢出中断请求标志。当定时/计
数器T0发生溢出时,置位TF0,并向CPU申请中断。
④T1(P3.5),TF1(TCON.7),片内定时/计数器T1溢出中断请求标志。当定时/计
数器T1发生溢出时,置位TF1,并向CPU申请中断。
⑤RI(SCON.0)或TI(SCON.1),串行口中断请求标志。当串行口接收完一帧串行
数据时置位RI或当串行口发送完一帧串行数据时置位TI,向CPU申请中断。
中断寄存器
定时器控制寄存器TCON
IT0:外部中断0触发方式控制位。当IT0=0时,为电平触发方式。当IT0=1时,为边沿触发方式(下降沿有效)。
IE0:外部中断0中断请求标志位。
IT1:外部中断1触发方式控制位。
IE1:外部中断1中断请求标志位。
TF0:定时/计数器T0溢出中断请求标志位。
TF1:定时/计数器T1溢出中断请求标志位。
中断允许寄存器IE
EX0:外部中断0允许位;
ET0:定时/计数器T0中断允许位;
EX1:外部中断0允许位;
ET1:定时/计数器T1中断允许位;
ES: 串行口中断允许位;
EA :CPU中断允许(总允许)位
中断优先级寄存器IP
PT2:定时器/计数器2中断优先级控制位(仅8052);1:高优先级,0:低优先级
PS:串行口优先级控制位;1:高优先级,0:低优先级
PT0/PT1:定时器/计数器0/1中断优先级控制位;1:高优先级,0:低优先级
PX0/PX1:外部中断管0/1中断优先级控制位;1:高优先级,0:低优先级
中断优先级
同一优先级中的中断申请不止一个时,则有中断优先权排队问题。
同一优先级的中断优先权排队,由中断系统硬件确定的自然优先级
决定。
*中断执行原则:
①CPU同时接收到几个中断时,首先响应优先级别最高的中断请求。
②正在进行的中断过程不能被新的同级或低优先级的中断请求所中
断。
③正在进行的低优先级中断服务,能被高优先级中断请求所中断。
中断的使用
中断响应条件
①中断源要有中断请求
②中断源的中断允许位为1
③打开总中断(即EA=1)
外部中断
外部中断0–控制LED
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
sbit k3=P3^2; sbit led=P2^0;
void delay(u16 i) { while(i--); }
void Int0Init() { IT0=1; EX0=1; EA=1; }
void main() { Int0Init(); while(1); }
void Int0() interrupt 0 { delay(1000); if(k3==0) { led=~led; } }
|
外部中断1–控制蜂鸣器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
sbit k4=P3^3; sbit beep=P1^5;
u8 beep_flag=0;
void delay(u16 i) { while(i--); }
void Int1Init() { IT1=1; EX1=1; EA=1; }
void main() { Int1Init(); while(1) { if(beep_flag==1) { beep=!beep; delay(10); } } }
void Int1() interrupt 2 { delay(1000); if(k4==0) { beep_flag=!beep_flag; } }
|
定时器和计数器
定时器/计数器简介
定时器/计数器(Timer/Counter,简称T/C)是单片机中最基本的接口之一。即可以定时又可以计数。常用于计数、延时、测量周期/脉宽/频率、提供定时脉冲信号等。
8051系列单片机至少含有2个16位的T/C,STC89C51/52含有3个T/C。其中2个为基本定时器/计数器T/C0和T/C1,另一个是T/C2。可通过软件配置为定时器功能或者计数器功能。
定时/计数器的工作原理: 定时/计数器实质上是一个加1计数器。当工作在定时器模式时,对振荡源12分频的脉冲计数,即每个机器周期计数值加1,当加到计数器为全1时,再输入一个脉冲就使计数器回零。当工作在计数器模式时,计数脉冲来至外部脉冲输入引脚P3.4(T0)和P3.5(T1),当T0或T1脚上负跳变时计数值加1 ,识别管脚负跳变需要2个机器周期,即24个振荡周期。所以T0或T1脚输入的可计数的外部脉冲的最高频率为1/24fosc,当晶振12MHZ时,最高计数频率为500KHz,高于此频率将计数出错。
定时器/计数器内部结构:
定时器/计数器寄存器
控制寄存器TCON
TF1:T1溢出中断请求标志位。
TR1:T1运行控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。
TF0:T0溢出中断请求标志位。
TR0:T0运行控制位。
工作方式寄存器TMOD
定时/计数器2控制寄存器T2CON
定时器/计数器工作方式
通过工作方式寄存器TMOD的M0和M1组合,形成了定时器/计数器的4种不同工作方式。T/C0和T/C1都可以工作在方式0、方式1、方式2工作,而方式3只有T/C0才能工作。
方式0
方式0为13位计数,由TL0的低5位(高3位未用)和TH0的8位组成。TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断请求。
方式1
方式1的计数位数是16位,由TL0作为低8位,TH0作为高8位,组成了16位加1计数器。
方式2
方式2为自动重装初值的8位计数方式。
方式3
方式3只适用于定时/计数器T0,工作方式3将T0分成为两个独立的8位计数器TL0和TH0。定时器T1处于方式3时相当于TR1=0,停止计数。
定时器/计数器使用方法
①对TMOD赋值,以确定T0和T1的工作方式。
②计算初值,并将其写入TH0、TL0或TH1、TL1。
③中断方式时,打开定时器中断(ET0/ET1)及总中断EA。
④使TR0或TR1置位,启动定时/计数器定时或计数
定时器/计数器初值计算:
假如要定时1ms,定时器初值是多少?
计数脉冲个数N=1ms/1us=1000个
定时器初值X=2^16-1000=65536-1000=64536=0XFC18
定时器中断
定时器0中断–控制LED
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
sbit led=P2^0;
void Timer0Init() { TMOD&=0XFC; TMOD|=0X01;
TH0=0XFC; TL0=0X18; ET0=1; EA=1; TR0=1; }
void main() { Timer0Init(); while(1); }
void Timer0() interrupt 1 { static u16 i; TH0=0XFC; TL0=0X18; i++; if(i==1000) { i=0; led=~led; } }
|
定时器1中断–控制数码管
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
sbit LSA=P3^0; sbit LSB=P3^1; sbit LSC=P3^3;
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; u8 n=0;
void Timer1Init() { TMOD|=0X10;
TH1=0XFC; TL1=0X18; ET1=1; EA=1; TR1=1; }
void main() { LSA=0; LSB=0; LSC=0; Timer1Init(); while(1); }
void Timer1() interrupt 3 { static u16 i; TH1=0XFC; TL1=0X18; i++; if(i==1000) { i=0; P0=smgduan[n++]; if(n==16)n=0; } }
|
简易交通灯
本节所要实现的功能是:系统运行时,横向通行绿灯亮10秒,然后黄灯亮3秒,纵向通行绿灯亮10秒,黄灯亮3秒。数码管显示倒计时。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
sbit LSA=P2^2; sbit LSB=P2^3; sbit LSC=P2^4;
sbit rd1=P2^0; sbit yd1=P2^1; sbit gd1=P2^2;
sbit rd2=P2^3; sbit yd2=P2^4; sbit gd2=P2^5;
u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; char sec1=0,sec2=0,sec3=0,sec4=0; u8 sec1flag=1,sec2flag,sec3flag,sec4flag;
void Timer1Init() { TMOD|=0X10;
TH1=0XFC; TL1=0X18; ET1=1; EA=1; TR1=1; }
void main() { LSA=1; LSB=1; LSC=1; Timer1Init(); while(1) { if(sec1<10&&sec1flag==1) { rd1=0; yd1=1; gd1=1;
rd2=1; yd2=1; gd2=0; P0=smgduan[9-sec1]; } if(sec2<4&&sec2flag==1) { rd1=0; yd1=1; gd1=1;
rd2=1; yd2=0; gd2=1; P0=smgduan[3-sec2]; } if(sec3<10&&sec3flag==1) { rd1=1; yd1=1; gd1=0;
rd2=0; yd2=1; gd2=1; P0=smgduan[10-sec3]; } if(sec4<4&&sec4flag==1) { rd1=1; yd1=0; gd1=1;
rd2=0; yd2=1; gd2=1; P0=smgduan[3-sec4]; } } }
void Timer1() interrupt 3 { static u16 i; TH1=0XFC; TL1=0X18; i++; if(i==1000) { i=0; if(sec1flag==1) { sec1++; if(sec1>9) { sec1=0; sec1flag=0; sec2flag=1; } } if(sec2flag==1) { sec2++; if(sec2>3) { sec2=0; sec2flag=0; sec3flag=1; } } if(sec3flag==1) { sec3++; if(sec3>9) { sec3=0; sec3flag=0; sec4flag=1; } } if(sec4flag==1) { sec4++; if(sec4>3) { sec4=0; sec4flag=0; sec1flag=1; } } } }
|
串口通信
通信的概念
通信的方式可以分为多种,按照数据传送方式可分为串行通信和并行通信。按照通信的数据同步方式,可分为异步通信和同步通信。按照数据的传输方向又可分为单工、半双工和全双工通信。
串行通信与并行通信
串行通信
串行通信是指使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度。其只需要少数几条线就可以在系统间交换信息,特别适用于计算机与计算机、计算机与外设之间的远距离通信。
特点:传输线少,长距离传送时成本低,且可以利用电话网等现成的设备,但数据的传送控制比并行通信复杂。
并行通信
并行通信通常是将数据字节的各位用多条数据线同时进行传送,通常是8位、16位、32位等数据一起传输。
特点:控制简单、传输速度快;由于传输线较多,长距离传送时成本高且接收方的各位同时接收存在困难,抗干扰能力差。
异步通信与同步通信
异步通信
异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。异步通信是以字符(构成的帧)为单位进行传输,字符与字符之间的间隙(时间间隔)是任意的,但每个字符中的各位是以固定的时间传送的,即字符之间不一定有“位间隔”的整数倍的关系,但同一字符内的各位之间的距离均为“位间隔”的整数倍。
特点:不要求收发双方时钟的严格一致,实现容易,设备开销较小,但每个字符要附加2~3位用于起止位,各帧之间还有间隔,因此传输效率不高。
同步通信
同步通信时要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的字符间不留间隙,即保持位同步关系,也保持字符同步关系。发送方对接收方的同步可以通过两种方法实现。
单工、半双工与全双工通信
单工通信
单工是指数据传输仅能沿一个方向,不能实现反向传输。
半双工通信
半双工是指数据传输可以沿两个方向,但需要分时进行。
全双工通信
全双工是指数据可以同时进行双向传输。
通信速率
衡量通信性能的一个非常重要的参数就是通信速率,通常以比特率(Bitrate)来表示。比特率是每秒钟传输二进制代码的位数,单位是:位/秒(bps)。如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的比特率为:10位×240个/秒 = 2400 bps
串口通信简介
串口通信(Serial Communication),是指外设和计算机间,通过数据信号线、地线等,按位进行传输数据的一种通信方式,属于串行通信方式。串口是一种接口标准,它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。
RS232的通信协议比较简单,通常遵循96-N-8-1格式。
串口内部结构
串口相关寄存器
串口控制寄存器SCON
SM0和SM1为工作方式选择位:
SM2:多机通信控制位,主要用于方式2和方式3。当SM2=1时可以利用收到的RB8来控制是否激活RI(RB8=0时不激活RI,收到的信息丢弃;RB8=1时收到的数据进入SBUF,并激活RI,进而在中断服务中将数据从SBUF读走)。当SM2=0时,不论收到的RB8为0和1,均可以使收到的数据进入SBUF,并激活RI(即此时RB8不具有控制RI激活的功能)。通过控制SM2,可以实现多机通信。
REN:允许串行接收位。由软件置REN=1,则启动串行口接收数据;若软件置REN=0,则禁止接收。
TB8:在方式2或方式3中,是发送数据的第9位,可以用软件规定其作用。可以用作数据的奇偶校验位,或在多机通信中,作为地址帧/数据帧的标志位。在方式0和方式1中,该位未用到。
RB8:在方式2或方式3中,是接收到数据的第9位,作为奇偶校验位或地址帧/数据帧的标志位。在方式1时,若SM2=0,则RB8是接收到的停止位。
TI:发送中断标志位。在方式0时,当串行发送第8位数据结束时,或在其它方式,串行发送停止位的开始时,由内部硬件使TI置1,向CPU发中断申请。在中断服务程序中,必须用软件将其清0,取消此中断申请。
RI:接收中断标志位。在方式0时,当串行接收第8位数据结束时,或在其它方式,串行接收停止位的中间时,由内部硬件使RI置1,向CPU发中断申请。也必须在中断服务程序中,用软件将其清0,取消此中断申请。
电源控制寄存器PCON
SMOD:波特率倍增位。在串口方式1、方式2、方式3时,波特
率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0。
串口工作方式
方式0
方式0时,串行口为同步移位寄存器的输入输出方式。主要用于扩展并行输入或输出口。数据由RXD(P3.0)引脚输入或输出,同步移位脉冲由TXD(P3.1)引脚输出。发送和接收均为8位数据,低位在先,高位在后。波特率固定为fosc/12。
①方式0输出
②方式0输入
方式1
方式1是10位数据的异步通信口。TXD为数据发送引脚,RXD为数据接收引脚,传送一帧数据的格式如下所示。其中1位起始位,8位数据位,1位停止位。
①方式1输出
②方式1输入
用软件置REN为1时,接收器以所选择波特率的16倍速率采样RXD引脚电平,检测到RXD引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位。当RI=0,且SM2=0(或接收到的停止位为1)时,将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置RI=1,向CPU请求中断。
方式2和方式3
方式2或方式3时为11位数据的异步通信口。TXD为数据发送引脚,
RXD为数据接收引脚 。
①方式2、方式3输出
发送开始时,先把起始位0输出到TXD引脚,然后发送移位寄存器的输出位(D0)到TXD引脚。每一个移位脉冲都使输出移位寄存器的各位右移一位,并由TXD引脚输出。 第一次移位时,停止位“1”移入输出移位寄存器的第9位上 ,以后每次移位,左边都移入0。当停止位移至输出位时,左边其余位全为0,检测电路检测到这一条件时,使控制电路进行最后一次移位,并置TI=1,向CPU请求中断。
②方式2、方式3输入
接收时,数据从右边移入输入移位寄存器,在起始位0移到最左边时,控制电路进行最后一次移位。当RI=0,且SM2=0(或接收到的第9位数据为1)时,接收到的数据装入接收缓冲器SBUF和RB8(接收数据的第9位),置RI=1,向CPU请求中断。如果条件不满足,则数据丢失,且不置位RI,继续搜索RXD引脚的负跳变。
串口的使用
(1)如何计算波特率
方式0的波特率 = fosc/12
方式2的波特率 =(2SMOD/64)· fosc
方式1的波特率 =(2SMOD/32)·(T1溢出率)
方式3的波特率 =(2SMOD/32)·(T1溢出率)
T1 溢出率 = fosc /{12×[256 -(TH1)]}
(2)串口初始化步骤
①确定T1的工作方式(TMOD寄存器);
②确定串口工作方式(SCON寄存器);
③计算T1的初值(设定波特率),装载TH1、TL1;
④启动T1(TCON中的TR1位);
⑤如果使用中断,需开启串口中断控制位(IE寄存器)。
串口模块电路
编写程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
#include "reg52.h"
typedef unsigned int u16; typedef unsigned char u8;
void UsartInit() { SCON=0X50; TMOD=0X20; PCON=0X80; TH1=0XF3; TL1=0XF3; ES=1; EA=1; TR1=1; }
void main() { UsartInit(); while(1); }
void Usart() interrupt 4 { u8 receiveData; receiveData=SBUF; RI = 0; SBUF=receiveData; while(!TI); TI=0; }
|