示例:sfr SCON = 0X98;
sbit LED = P0^2;
C51中常用的一些预处理命令#define
#define A P0
注意后面不需要加分号
#typedef
typedef unsigned char int;
注意后面的分号
重新定义一些常用的关键字可以增强程序的可移植性,因为C语言数据类型关键字的位宽在不同的编译软件上是不同的。
#ifndef…#endif
条件编译,常用于头文件的定义以及一些程序的条件编译
C51基本数据类型类型符号关键字占用位数的表示范围
整数
有
(签名)整数
16
-32768~32767
(签名)短
16
-32768~32767
(签名)长
32
-2147483648~2147483647
没有任何
无符号整数
16
0~65535
无符号短整型
16
0~65535
无符号长整型
32
0~4294967295
真实类型
有
漂浮
32
3.4e-38~3.4e38
双倍的
64
1.7e-308~1.7e308
字符类型
字符
-128~127
没有任何
无符号字符
0~255
常用运算符
+、-、*、/(加、减、乘、除)
>、>=、许可证管理…>>复制CID代码>>打开破解工具>>粘贴CID代码>>点击Generate生成密钥并复制>>返回Keil软件后点击Add Lic粘贴密钥
创建项目模板
步骤一:新建工程:打开Keil软件,选择Projet >> New μVision Projet… >> 选择保存路径,命名为Template >> 弹出提示后点击Cancel >> 在Atmel中选择AT89C52或AT89C51 >> 弹出点击否的提示框
第二步:新建一个主程序,选择文件>>新建>>命名为main.c>>将以下代码粘贴到编辑区:
#include "reg52.h"
void main() {
while(1) {
}
}
第三步:右键点击新建项目Source Group 1,选择Add Files to Group 'Source Group 1…,添加刚才创建的main.c文件。
第四步,点击Build,编译程序,确保程序正确。
步骤 4:单击“目标选项…”图标,单击“输出”选项卡,选中“创建 HEX 文件”选项,然后单击“确定”
配置Sublime text编译51个程序
{
"shell_cmd": ""%KEIL_CMD%/C51" "${file}" & "%KEIL_CMD%/LX51" "${file_base_name}.obj" to "${file_base_name}.abs" >> nul & "%KEIL_CMD%/OHx51" "${file_base_name}.abs" >> nul & DEL *.lst *.obj *.map *.abs >> nul",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"working_dir": "${file_path}",
"selector": "source.c",
"encoding":"cp936"
}
其中%KEIL_CMD%是Keil软件安装路径的环境变量,需要手动配置。 我的环境变量配置如下:
01. 点亮 LED 灯。 什么是LED?
LED,即发光二极管,是一种半导体固体发光器件。 如图所示:
LED工作原理
LED的工作是有方向性的。 只有正极接LED阳极,负极接LED负极时才能工作。 如果 LED 接反,将无法正常工作。
看懂原理图
开发板上LED的原理图如下所示。 LED的阳极串联一个电阻,然后连接到电源VCC。 LED的负极连接到微控制器的P2端口。 如果要点亮LED,只需连接单片机相应的IO即可。 分配到低级别。
司机
C语言知识点:
sbit变量名=地址值;
命名引脚时经常使用它。
#include "reg52.h"
sbit led = P2^0;
void main(){
while(1){
led = 0;
}
}
02.LED闪烁C语言知识typedef
typedef unsigned char u8;
typedef unsigned int u16;
重新定义一些常用的关键字可以增强程序的可移植性,因为C语言数据类型关键字的位宽在不同的编译软件上是不同的。
while 循环
while(i < 10) {
i = i + 1;
}
while语句的语义是:计算表达式的值,当该值为真(非零)时,执行循环体语句。
延迟功能
void delay (u16 i) { //大约延时10us
while(i--);
}
司机
/*
实验现象:使第一个LED不停地闪烁
*/
#include "reg52.h"
typedef unsigned int u16;
sbit led = P2^0;
void delay(u16 i){
while(i--);
}
void main(){
while(1){
delay(50000);
led = ~led;
}
}
03.流水灯定义宏
#define A P0
将所有 A 替换为 P0
循环左移右移函数
_crol_(a,b); 循环左移函数,a为要左移的值,b为要左移的位数。
_cror_(a,b); 循环右移函数,a为要右移的值,b为要右移的位数。
以上两个函数包含在instrins.h库函数中。
驱动方法①
/*
实验现象:LED灯来回流动点亮
*/
#include "reg52.h"
#include
typedef unsigned int u16;
typedef unsigned char u8;
#define LED P2
void delay(u16 i) {
while(i--);
}
void main() {
u8 flag = 0, i = 0;
LED = ~0x01;
while(1) {
delay(50000);
if (!(i++ % 7)) flag = !flag;
LED = flag ? _crol_(LED,1) : _cror_(LED,1);
}
}
方法②
void main() {
u8 v = 1, i = 0;
while(1) {
LED = 0xff ^ 1 << i;
i += v;
if (i >= 7 || i <= 0) v *= -1;
delay(50000);
}
}
04.蜂鸣器
从图中识别蜂鸣器:有绿色电路板的为无源蜂鸣器,无电路板并用黑胶密封的为有源蜂鸣器。
接通电源后,振荡器产生的音频信号电流通过电磁线圈,使电磁线圈产生磁场。 振膜在电磁线圈和磁铁的相互作用下产生周期性振动并产生声音。
多谐振荡器由晶体管或集成电路组成。 当电源接通(1.5~15V DC工作电压)时,多谐振荡器开始振动并输出1.5~2.5kHZ的音频信号。 阻抗匹配器驱动压电蜂鸣器。 讲出。
在单片机应用的设计中,很多方案都会用到蜂鸣器,大多数都是利用蜂鸣器来提供提示或者报警,比如按钮按下、工作开始、工作结束或者故障等。
自激式蜂鸣器采用直流电压驱动,不需要交流信号驱动。 只需要向驱动端口输出驱动电平,通过放大电路放大驱动电流即可使蜂鸣器发声。 这很简单。
通过改变单片机引脚输出波形的频率,可以调节和控制蜂鸣器的音调,从而产生不同音色、音调的各种声音。
通过改变输出电平高低电平占空比,可以控制蜂鸣器的音量大小。
电路原理图
ULN2003简介
ULN2003是高压大电流达林顿阵列,由七个硅NPN达林顿管组成。
ULN2003是一款大电流驱动阵列,主要应用于微控制器、智能电表、PLC、数字输出卡等控制电路。 可直接驱动蜂鸣器、继电器等负载。
司机
#include "reg52.h"
typedef unsigned int u16;
sbit beep = P2^5;
void delay(u16 i) {
while(i--);
}
void main() {
while(1) {
beep = ~beep;
delay(100); // 通过修改此延时时间达到不同的发声效果
}
}
知识拓展
可以通过改变输出波形的频率来模拟音乐,形成不同的音调,例如:
#include "reg52.h"
#define RldTmr(fr) 65536 - (11059200 / 12) / (fr << 1)
#define FuDian(n) (n << 1) / 3 //附点n分音符的换算
typedef unsigned char UCHAR;
typedef unsigned int UINT;
typedef unsigned long ULONG;
sbit BUZZ = P2^5;
UINT code noteFreq[] = { //中音 1-7 和高音 1-7对应的频率列表
523, 587, 659, 698, 784, 880, 988,
1047, 1175, 1319, 1397, 1568, 1760, 1976
};
UINT code tmrRld[] = { //中音 1-7 和高音 1-7对应的定时器重载值
RldTmr(523), RldTmr(587), RldTmr(659), RldTmr(698), RldTmr(784), RldTmr(880), RldTmr(988),
RldTmr(1047), RldTmr(1175), RldTmr(1319), RldTmr(1397), RldTmr(1568), RldTmr(1760), RldTmr(1976),
};
UCHAR code musicNote[] = { //音名
1, 2, 3, 1,
1, 2, 3, 1,
3, 4, 5,
3, 4, 5,
5, 6, 5, 4, 3, 1,
5, 6, 5, 4, 3, 1,
1, 5, 1,
1, 5, 1
};
UCHAR code noteDuration[] = { //音名对应的时值,4表示4分音符,8表示8分音符,16表示16分音符
4, 4, 4, 4,
4, 4, 4, 4,
4, 4, 2,
4, 4, 2,
FuDian(8), 16, FuDian(8), 16, 4, 4,
FuDian(8), 16, FuDian(8), 16, 4, 4,
4, 4, 2,
4, 4, 2
};
bit enable = 1, tmrFlg = 0;
UCHAR T0RH = 0XFF, T0RL = 0X00;
void Delay(UINT n);
void PlayMusic(UCHAR speed); //固定标准为4分音符的速度:例如speed = 108 表示一分钟扫过108个4分音符
void main() {
EA = 1;
TMOD = 0X01;
TH0 = T0RH;
TL0 = T0RL;
ET0 = 1;
TR0 = 1;
while (1) {
PlayMusic(72);
Delay(40000u);
}
}
void Delay(UINT n) {
while(n--);
}
void PlayMusic(UCHAR speed) {
UCHAR i;
UCHAR idx;
UINT cnt = 0;
UINT durationCnt = 0; //当前音符的时值对应的定时器计数
UINT soundCnt = 0; //当前音符的发声时值对应的计数值
for (i = 0; i < sizeof (musicNote); ) {
while (!tmrFlg) ;
tmrFlg = 0;
if (cnt == 0) {
idx = musicNote[i] - 1;
T0RH = tmrRld[idx] >> 8;
T0RL = tmrRld[idx];
durationCnt = (ULONG)240 * (ULONG)noteFreq[idx] / ((ULONG)noteDuration[i] * (ULONG)speed);
soundCnt = durationCnt - (durationCnt >> 2); //当前音符时值的前3/4发声,后1/4静音
enable = 1;
cnt++;
} else {
if (cnt == durationCnt) {
cnt = 0;
i++;
} else {
cnt++;
if (cnt == soundCnt) {
enable = 0;
}
}
}
}
}
void InterruptTmr0() interrupt 1 {
TH0 = T0RH;
TL0 = T0RL;
tmrFlg = 1;
if (enable)
BUZZ = ~BUZZ;
else
BUZZ = 1;
}
05.静态数码管如何显示字符?
显示及其接口
微控制器系统中常用的显示器包括:发光二极管(LED)显示器、液晶显示器(Liquid Crystal Display)显示器、TFT LCD显示器等。LED显示器有两种显示结构:段码显示(7段、米形、等)和点阵显示(5×8、8×8点阵等)。
LED数码管根据LED连接方式的不同可分为共阴极和共阳极两大类。
在使用LED显示屏时,要注意区分这两种不同的连接方式。 为了显示数字或字符,必须对数字或字符进行编码。 七段数码管加一位小数点,共8段。 因此,为LED显示屏提供的编码正好是一个字节。 我们的实验板采用的是共阴LED显示屏。 根据电路连接图,十六进制编码如下表所示。
代码值 显示值 代码值 显示数据
0x3f
0x7f
0x06
0x6f
0x5b
0x77
0x4f
0x7c
0x66
0x39
0x6d
0x5e
0x7d
0x79
0x07
0x71
0x00
无显示
数码管静态显示原理
LED显示屏有两种工作模式:静态显示模式和动态显示模式。 静态显示的特点是每个数码管的段选必须连接一条8位数据线来维持显示的字形码。 发送一次字形代码后,可以保留显示的字形,直到发送新的字形代码。 这种方法的优点是占用CPU时间少,且显示易于监视和控制。 缺点是硬件电路较复杂,成本较高。
开发板数码管电路图
74H573锁存器的使用
OE为使能端。 当为低电平时,锁存器开始工作。 VCC和GND是电源和接地端。 LE 是锁存端。 当LE为高电平时,Q0Q7与D0D7状态相同。 当LE为低电平时,Q0Q7锁存数据。 无论D0D7如何变化,Q0~Q7保持锁存前的状态。驱动器
实施例1
/*
实验现象:动态数码管从左至右显示0-7
*/
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
// 数码管片选信号引脚(3-8译码器)
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
// 显示0~F的值
u8 code smgduan[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
// 休眠函数
void delay(u16 i) {
while(i--);
}
// 数码管动态扫描函数,循环扫描8个数码管显示
void DigDisplay() {
u8 i;
for(i = 0; i < 8; i++) {
//位选,选择点亮的数码管
LSA = !(i&1);
LSB = !(i&2);
LSC = !(i&4);
// 发送数据给数码管
P0 = smgduan[i];
// 间隔一段时间扫描
delay(100);
// 消隐
P0 = 0x00;
}
}
void main() {
while(1) {
DigDisplay(); //数码管显示函数
}
}
06.动态数码管数码管动态显示原理
动态显示的特点是所有数码管的段选择线并联,位选择线控制哪一个数码管有效。 所选数码管采用动态扫描显示。 所谓动态扫描显示,就是依次向各个数码管发送字形代码和相应的位选择。 它利用发光管的余辉和人类视觉的暂留作用,使人感觉好像所有数码管都在同时显示。 动态显示的亮度比静态显示的亮度差,因此选择限流电阻时应比静态显示电路中的限流电阻稍小。
74HC138解码器的使用
D74HC138D是一款三通道输入、八通道输出的解码器,主要应用于消费类电子产品。
适用于数字电路中的3-8位译码功能
引脚说明
名称 功能描述 引脚号
Y0‾overline{Y0}Y0 — Y6‾overline{Y6}Y6, Y7‾overline{Y7}Y7
数据输出
15 — 9, 7
A0A0A0 — A2A2A2
数据输入
1 — 3
E1‾上线{E1}E1,E2‾上线{E2}E2,E3E3E3
启用控制
4 — 6
电源电压 电源电压
逻辑电源
16
GNDGNDGND
逻辑上
逻辑图
真值表
司机
/*
实验现象:动态数码管从左至右显示1314520,并循环右移
*/
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
// 数码管片选信号引脚(3-8译码器)
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
// 显示1314520的值
u8 code smgduan[] = {0x06,0x4f,0x06,0x66,0x6d,0x5b,0x3f};
// 休眠函数
void delay(u16 i) {
while (i--);
}
// 数码管动态扫描函数,循环扫描8个数码管显示
void DigDisplay() {
static u8 n = 0, m = 0;
u8 i;
for (i = 0; i < 7; i++) {
//位选,选择点亮的数码管
LSA = !(i + m & 1);
LSB = !(i + m & 2);
LSC = !(i + m & 4);
// 发送数据给数码管
P0 = smgduan[i];
// 间隔一段时间扫描
delay(100);
// 消隐
P0 = 0x00;
}
// 间隔一段时间后左移一位数码管
if (!(++n % 100)) {
++m;
n = 0;
m %= 7;
}
}
void main() {
while (1) {
DigDisplay(); //数码管显示函数
}
}
07.独立按钮介绍
轻触开关是一种电子开关。 使用时,轻按开关按钮即可打开开关。 当您松开手时,开关就会关闭。 我们使用的开关如下图所示:
独立按键原理
当按钮闭合和打开时,触点会振动。
硬件去抖电路
司机
/*
实验现象:按 k1 ~ k4 按钮数码管显示1~4的数字
*/
#include "reg52.h"
typedef unsigned char u8;
typedef unsigned int u16;
// 四个独立按钮串口
sbit k1 = P3^1;
sbit k2 = P3^0;
sbit k3 = P3^2;
sbit k4 = P3^3;
// 38译码器串口
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
// 数码管显示1、2、3、4对应的16进制信号
u8 code smgduan[16] = {0x06,0x5b,0x4f,0x66};
// 延时函数
void delay(u16 i) {
while(i--);
}
// 处理按钮按下函数
void keyPress() {
static u8 key = 0;
// 判断按下了哪个按钮
if (k1 == 0) {
delay(1000); // 消抖
if (k1 == 0) key = 1;
} else if (k2 == 0) {
delay(1000); // 消抖
if (k2 == 0) key = 2;
} else if (k3 == 0) {
delay(1000); // 消抖
if (k3 == 0) key = 3;
} else if (k4 == 0) {
delay(1000); // 消抖
if (k4 == 0) key = 4;
}
// 根据按下的按钮显示数字
if (key) P0 = smgduan[key-1];
key = 0;
delay(100);
}
void main() {
u8 i = 0;
while(1) {
keyPress();
}
}
08. 矩阵按钮 矩阵按钮的由来
矩阵按键扫描原理
方法一:
逐行扫描:通过高四位依次输出低电平,可以对矩阵键盘进行逐行扫描。 当接收到的数据低四位不全为1时,说明有按键被按下,然后通过接收到的数据中哪一位为0来判断是哪个按键被按下。
方法二:
行列扫描:高四位全部输出低电平,低四位输出高电平。 当接收到的数据的低四位不全是高电平时,表示有按钮被按下。 然后根据接收到的数据值,判断哪一列有按钮被按下,然后反过来,高四位输出高电平。 低四位输出低电平,然后根据接收到的高四位值来判断哪一行有按钮被按下,从而可以确定哪个按钮被按下。
如何将矩阵按钮变成独立的按钮驱动器
/*
实验现象:按矩阵按钮,数码管依次显示0~15的数字
*/
#include "reg52.h"
typedef unsigned char u8;
typedef unsigned int u16;
#define GPIO_DIG P0
#define GPIO_KEY P1
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
u8 code smgduan[17] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; //共阴
u8 keyValue;
void delay(u16 i) {
while(i--);
}
void keyDown()
{
char a = 0;
GPIO_KEY = 0x0f;
if (GPIO_KEY != 0x0f) {
delay(1000);
if (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;
default: break;
}
GPIO_KEY = 0xf0;
switch(GPIO_KEY) {
case (0x70): keyValue = keyValue; break;
case (0xb0): keyValue += 4; break;
case (0xd0): keyValue += 8; break;
case (0xe0): keyValue += 12; break;
default: break;
}
while(a < 50 && GPIO_KEY != 0xf0) {
delay(5);
a++;
}
}
}
}
void lightedDig() {
switch(keyValue) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
LSA = 1; LSB = 1; LSC = 1;
GPIO_DIG = ~smgduan[keyValue];
break;
default:
GPIO_DIG = ~smgduan[1];
LSA = 1; LSB = 1; LSC = 1;
delay(100);
GPIO_DIG = ~smgduan[keyValue % 10];
LSA = 0; LSB = 1; LSC = 1;
delay(100);
break;
}
}
void main() {
while(1) {
keyDown();
// GPIO_DIG = ~smgduan[keyValue];
lightedDig();
}
}
09.单片机IO扩展-74HC595 74HC595芯片介绍
8 位串行输入/输出或并行输出移位寄存器,具有高阻抗关断状态、三态。
595 是一款具有存储器和三态输出功能的 8 位移位寄存器。
移位寄存器和存储器分别是两个时钟。
数据在SCHcp的上升沿输入,在STcp的上升沿进入存储寄存器。 如果两个时钟连接在一起,移位寄存器总是比存储寄存器领先一个脉冲。
移位寄存器具有串行移位输入(Ds)、串行输出(Q7')和异步低电平复位。 存储寄存器具有并行 8 位、三态总线输出。 当OE使能(低电平)时,存储寄存器中的数据输出到总线。
特性 输出能力 应用
引脚说明 符号 引脚说明
质量保证~QH
15.1~7
并行数据输出
接地
土地
QH'
串行数据输出
SRLR
10
主复位(低电平)
SRCLK
11
移位寄存器时钟输入
时钟脉冲
12
存储寄存器时钟输入
OE
13
输出有效(低电平)
塞内尔
14
串行数据输入
电压控制电路
16
电源
菜单输入输出功能
SRCLK
时钟脉冲
OE
SRLR
塞内尔
QH'
Qn
×
×
↓
×
数控
当MR为低电平时,仅影响移位寄存器。
×
↑
×
清空移位寄存器到输出寄存器。
×
×
×
清零移位寄存器并将并行输出置于高阻状态。
↑
×
QG'
数控
逻辑高电平被移位到移位寄存器状态0,包含移位到例如串行输出位中存在的先前状态G(内部QG')的所有移位寄存器状态。
×
↑
×
数控
Qn'
移位寄存器的内容被传送到保持寄存器并从并行端口输出。
↑
↑
×
QG'
Qn'
移位寄存器的内容移入,前一个移位寄存器的内容到达保持寄存器并输出。
注:H = 高电平状态,L = 低电平状态,↑ = 上升沿,↓ = 下降沿,Z = 高阻,NC = 无变化,× = 无效
当SRCLR为高电平、OE为低电平时,数据在SRCLK上升沿进入移位寄存器,并在RCLK上升沿输出到并行口。
74595 数据端子: 74595 控制端子 说明:
注:74164和74595功能类似,都是8位串行输入并行输出移位寄存器。 74164(25mA)的驱动电流比74595(35mA)小。 14 引脚封装的尺寸也更小。 74595的主要优点是它有一个数据存储寄存器。 在移位过程中,输出端的数据可以保持不变。 这在串口速度慢,且数码管不闪烁的情况下非常有用。 与164仅具有数据清除端相比,595还具有输出端来使能/禁用控制端,可以使输出处于高阻状态。 另外,根据网上报价,164片的价格为每片1元,595片的价格为每片0.8元。
计划说明
每当spi_shcp的上升沿到来时,spi_ds引脚的当前电平值在移位寄存器中左移一位。 当下一个上升沿到来时,移位寄存器中的所有位将左移一位。 同时,QH'也将移位寄存器中的高位值串行输出。 如果连续进行8次,则可以将数组中的每个数字(8位数字)发送到移位寄存器; 那么当spi_stcp的上升沿到来时,移位寄存器的值就会被锁存到锁存器中并从QA~QH引脚输出
司机
/*
实验现象:点亮点阵左下角的LED
*/
#include "reg51.h" //此文件中定义了单片机的一些特殊功能寄存器
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;
// 定义使用的IO口
sbit SRCLK = P3^6; // 移位寄存器时钟输入口
sbit RCLK = P3^5; // 存储寄存器时钟输入口
sbit SER = P3^4; // 串行数据输入
sbit LED = P0^7; // 点阵P0口,后面数字对应点阵列号
// 延时函数
void delay(u16 i) {
while(i--);
}
// 向74H595发送一个字节的数据
void Hc595SendByte(u8 dat) {
u8 a;
SRCLK = 1;
RCLK = 1;
for(a = 0; a < 8; a++) { // 发送8位数
SER = dat >> 7; // 从最高位开始发送
dat <<= 1;
SRCLK = 0; // 发送时序
_nop_(); // 延时两个机器周期
_nop_();
SRCLK = 1;
}
RCLK = 0;
_nop_(); // 延时两个机器周期
_nop_();
RCLK = 1;
}
void main() {
LED = 0; //使第一列为低电平。
while(1) {
Hc595SendByte(0xfe,0x01);
}
}
10、LED点阵原理 8×8 LED点阵
什么是点阵
点阵简介
8×8 LED点阵动态显示
驱动示例一
/*
实验现象:8*8LED点阵第一列从下到上流动显示
*/
#include "reg51.h" //此文件中定义了单片机的一些特殊功能寄存器
#include "intrins.h"
typedef unsigned char u8;
typedef unsigned int u16;
// 定义使用的IO口
sbit SRCLK = P3^6; // 移位寄存器时钟输入口
sbit RCLK = P3^5; // 存储寄存器时钟输入口
sbit SER = P3^4; // 串行数据输入
sbit LED = P0^7; // 点阵P0口,后面数字对应点阵列号
// 延时函数
void delay(u16 i) {
while(i--);
}
// 向74H595发送一个字节的数据
void Hc595SendByte(u8 dat) {
u8 a;
SRCLK = 1;
RCLK = 1;
for(a = 0; a < 8; a++) { // 发送8位数
SER = dat >> 7; // 从最高位开始发送
dat <<= 1;
SRCLK = 0; // 发送时序
_nop_(); // 延时两个机器周期
_nop_();
SRCLK = 1;
}
RCLK = 0;
_nop_(); // 延时两个机器周期
_nop_();
RCLK = 1;
}
void main() {
u8 ledNum = 0x01; // 使第一行为高电平
LED = 0; // 使第一列为低电平
while(1) {
Hc595SendByte(ledNum);
ledNum = _crol_(ledNum, 1); // 循环左移
delay(50000);
}
}
实施例2
/*
实验现象:LED点阵显示爱心图像
*/
#include "reg51.h" //此文件中定义了单片机的一些特殊功能寄存器
#include "intrins.h"
typedef unsigned char u8;
typedef unsigned int u16;
// 定义使用的IO口
sbit SRCLK = P3^6; // 移位寄存器时钟输入口
sbit RCLK = P3^5; // 存储寄存器时钟输入口
sbit SER = P3^4; // 串行数据输入
// 心形显示需要点亮的图形点阵数据
u8 ledduan[] = {0x38,0x44,0x42,0x21,0x42,0x44,0x38,0x00},
ledwei[] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
// 延时函数
void delay(u16 i) {
while(i--);
}
// 向74H595发送一个字节的数据
void Hc595SendByte(u8 dat) {
u8 a;
SRCLK = 0;
RCLK = 0;
for(a = 0; a < 8; a++) { // 发送8位数
SER = dat >> 7; // 从最高位开始发送
dat <<= 1;
SRCLK = 1; // 发送时序
_nop_(); // 延时两个机器周期
_nop_();
SRCLK = 0;
}
RCLK = 1;
_nop_(); // 延时两个机器周期
_nop_();
RCLK = 0;
}
void main() {
u8 i;
while(1)
for(i = 0; i < 8; i++) {
P0 = ledwei[i]; //位选
Hc595SendByte(ledduan[i]); //发送段选数据
delay(100); //延时
Hc595SendByte(0x00); //消隐
}
}
实例三
/*
实验现象:点阵闪烁显示“洁”、心形图案
*/
#include "reg51.h" //此文件中定义了单片机的一些特殊功能寄存器
#include
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
// 定义使用的IO口
sbit SRCLK = P3^6; // 移位寄存器时钟输入口
sbit RCLK = P3^5; // 存储寄存器时钟输入口
sbit SER = P3^4; // 串行数据输入
// 点阵段选数据
u8 ledduan[][8] = {{0x40,0x57,0xF5,0x57,0x40,0x00,0x4A,0x91}, // 洁
{0x78,0xFC,0x3E,0x1F,0x1F,0x3E,0xFC,0x78}}, // 心
// 点阵位选数据
ledwei[] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};
void delay(u16 i) {
while(i--);
}
// 向74H595发送一个字节的数据
void Hc595SendByte(u8 dat) {
u8 a;
SRCLK = 0;
RCLK = 0;
for (a = 0; a < 8; a++) { // 发送8位数
SER = dat >> 7; // 从最高位开始发送
dat <<= 1;
SRCLK = 1; // 发送时序
_nop_(); // 延时两个机器周期
_nop_();
SRCLK = 0;
}
RCLK = 1;
_nop_(); // 延时两个机器周期
_nop_();
RCLK = 0;
}
void main() {
u8 i, j = 0, n = 1;
while(1) {
for(i = 0; i < 8; i++) {
P0 = ledwei[i]; // 位选
Hc595SendByte(ledduan[j][i]); // 发送段选数据
delay(100); // 延时
Hc595SendByte(0x00); // 消隐
}
if (n % 100 == 0) { // 间隔一段时间后切换显示的图形
n = 0;
j = !j;
}
n++;
}
}
11.中断系统中断的概念
当CPU正在处理一个事件A的同时,另一个事件B发生了,需要CPU快速处理(发生中断);
CPU暂时中断当前工作,转入处理事件B(中断响应和中断服务);
CPU处理完事件B后,会回到事件A被中断的地方,继续处理事件A(中断返回)。 这个过程称为中断。
51单片机中断系统结构
CPU中断的来源称为中断源。 中断源向CPU发出中断请求。 CPU暂时中断原来的事务A,转而处理事件B。处理完事件B后,返回到原来中断的地方(即断点)称为中断返回。 实现上述中断功能的组件称为中断系统。
随着计算机技术的应用,人们发现中断技术不仅解决了快速主机与慢速I/O设备**之间的数据传输问题,而且还具有以下优点:
89C51/52的中断系统有5个中断源和2个优先级,可以实现两级中断嵌套。
IT0(TCON.0)可以选择低电平有效或下降沿有效。 当CPU检测到P3.2引脚上有有效中断信号时,中断标志IE0(TCON.1)置1,并向CPU申请中断。 IT1(TCON.2)可以选择是低电平有效还是下降沿有效。 当CPU检测到P3.3引脚上有有效中断信号时,中断标志IE1(TCON.3)置1,并向CPU请求中断。 TF0(TCON.5),片内定时器/计数器T0溢出中断请求标志。 当定时器/计数器T0溢出时,TF0被置位并向CPU请求中断。 TF1(TCON.7),片内定时器/计数器T1溢出中断请求标志。 当定时器/计数器T1溢出时,TF1被置位并向CPU请求中断。 RI(SCON.0)或**TI**(SCON.1),串口中断请求标志位。 当串口收到一帧串行数据时置位RI,或当串口发送一帧串口数据时置位TI,向CPU请求中断。中断使能控制
CPU对中断系统中所有中断以及某个中断源的开启和阻止都是由中断使能寄存器IE来控制的。
少量
字节地址:A8H
EA
ES
ET1
EX1
ET0
EX0
IE
中断请求标志
TCON 中断标志
少量
字节地址:88H
TF1
TR1
TF0
TR0
IE1
信息技术1
IE0
信息技术0
总控
IE0(TCON.1),外部中断0中断请求标志。
IT1(TCON.2),外部中断1触发方式控制位。
IE1(TCON.3),外部中断1中断请求标志。
TF0(TCON.5),定时器/计数器T0溢出中断请求标志。
TF1(TCON.7),定时器/计数器T1溢出中断请求标志。
当同一优先级有多个中断申请时,就会出现中断优先级排队问题。 相同优先级的中断优先级队列由中断系统硬件决定的自然优先级组成,其排列如下:
各中断源响应优先级及中断服务程序入口表
中断源、中断标志、中断服务程序入口、优先级入口
外部中断0(INT0)
IE0
0003H
高的
定时器/计数器0(T0)
TF0
000BH
↓
外部中断1(INT1)
IE1
0013H
↓
定时器/计数器1 (T1)
TF1
001BH
↓
串行端口
RI 或 TI
0023H
低的
中断源
中断源符号名称 中断原因中断号
INT0
外部中断0
P3.2引脚低电平或下降沿信号
T0
定时器0中断
定时器/计数器0计数回0并溢出
INT1
外部中断1
P3.3引脚低电平或下降沿信号
T1
定时器1中断
定时器/计数器1计数回0并溢出
TI/RI
串口中断
串行通信完成一帧数据的发送或接收并产生中断。
51单片机中断优先级的三个原则
为了实现上面提到的最后两个原理,中断系统配备了两个用户无法寻址的优先级状态触发器。 其中之一设置为1,表示正在响应高优先级中断,这会阻塞所有后续的中断请求; 另一个设置为1,表示正在响应低优先级中断,并且会阻塞所有后续的低优先级中断请求。
中断处理流程
中断响应条件
只有同时满足以上三个条件,CPU才能响应中断。
要使用中断,程序员需要做什么?
以外部中断0为例,主程序中需要如下代码:
EA = 1; //打开总中断开关
EX0 = 1; //开外部中断0
IT0 = 0/1; //设置外部中断的触发方式
中断服务函数:
void int0 () interrupt 0 using 1 {
do anything that you want
}
驱动程序外部中断0实例
/*
实验现象:K3按钮控制第一个LED的开关
*/
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit LED = P2^0; // 定义P20口为LED
sbit K3 = P3^2; // 定义按钮K3
// 延时函数
void delay(u16 n) {
while(n--);
}
// 初始化外部中断0的响应条件
void Int0Init() {
IT0 = 1; // 触发方式设置为“边沿触发”方式(下降沿)
EX0 = 1; // 打开INT0的中断允许。
EA = 1; // 打开总中断
}
void main() {
Int0Init(); // 设置外部中断0
while(1);
}
// 外部中断0的中断函数
void Int0() interrupt 0 {
delay(1000); // 延时消抖
if (K3 == 0)
LED = ~LED;
}
外部中断1个实例
/*
实验现象:K4按钮控制第一个LED的开关
*/
#include "reg52.h"
typedef unsigned char u8;
typedef unsigned int u16;
sbit LED = P2^0; // 定义P20口为LED
sbit K4 = P3^3; // 定义按钮K4
// 延时函数
void delay(u16 i) {
while(i--);
}
// 初始化外部中断1的响应条件
void Int1Init() {
IT1 = 1; // 触发方式设置为“边沿触发”方式(下降沿)
EX1 = 1; // 打开INT1的中断允许。
EA = 1; // 打开总中断
}
void main() {
Int1Init(); // 设置外部中断1
while(1);
}
// 外部中断1的中断函数
void Int1() interrupt 2 {
delay(1000); // 延时消抖
if (K4 == 0)
LED = ~LED;
}
12.定时器和计数器CPU时序知识
例如:当外部晶振为12MHz时,51单片机相关周期的具体值为:
定时器/计数器的基础知识 定时器/计数器的工作原理
定时器/计数器本质上是一个加1计数器。 随计数器输入脉冲而加1,即每来一个脉冲,计数器自动加1。当计数器全为1时,再输入一个脉冲,计数器将归零,溢出counter 将导致计数器返回到零。 相应的中断标志位被设置为1并向CPU发出中断请求(当定时器/计数器中断使能时)。 如果定时器/计数器工作在计时模式,则表示计时时间已到; 如果工作在计数模式,则表示计数值已满。
可以看出,加1计数器的计数值是溢出时计数器的值减去初始计数值得到的。
51单片机定时器结构
定时器/计数器的本质是一个加1计数器(16位),由两个寄存器THx和TLx组成,分别为高8位和低8位。 TMOD是定时器/计数器的工作模式寄存器,决定了定时器/计数器的工作模式和功能; TCON是控制寄存器,控制T0和T1的启动和停止,并设置溢出标志。
定时器/计数器控制
51单片机定时器/计数器的工作是由两个特殊功能寄存器控制的。 TMOD用于设置其工作模式; TCON用于控制其启动和中断应用程序。
1.工作模式寄存器TMOD
工作模式寄存器TMOD用于设置定时器/计数器的工作模式。 低四位用于T0,高四位用于T1。 其格式如下:
少量
字节地址:89H
门
电/电
M1
莫0
门
电/电
M1
莫0
TMOD
GATE 是门控制位。 当GATE=0时,用于控制定时器的启动是否受外部中断源信号影响。 只要用软件将TCON中的TR0或TR1置1,即可启动定时器/计数器操作; 当GATA=1时,需要用软件将TR0或TR1置1,同时当外部中断引脚INT0/1也为高电平时,才可以启动定时器/计数器工作。 即此时定时器的启动条件加上了INT0/1引脚为高电平的条件。
C/T:定时/计数模式选择位。 C/T = 0 为定时模式; C/T = 1 为计数模式。
M1M0:工作模式设置位。 定时器/计数器有四种工作模式。
定时器/计数器工作模式设置表 M1M0工作模式说明
00
模式0
13位定时器/计数器
01
方式一
16位定时器/计数器
10
方式2
8 位自动重载定时器/计数器
11
方式3
T0分为两个独立的8位定时器/计数器; T1在此模式下停止计数
2.控制寄存器TCON
TCON的低4位用于控制外部中断,前面已经介绍过。 TCON的高4位用于控制
设置时间/计数器启动和中断请求。 其格式如下:
少量
字节地址:88H
TF1
TR1
TF0
TR0
总控
TF1(TCON.7):T1溢出中断请求标志位。 当T1计数溢出时,TF1由硬件自动置1。 CPU响应中断后,TF1自动被硬件清0。 当T1工作时,CPU可以随时查询TF1的状态。 因此,TF1可以作为查询测试的标志。 TF1也可以通过软件置1或清0,与硬件置1或清1效果相同。
TR1(TCON.6):T1操作控制位。 当TR1置1时,T1开始工作; 当TR1设置为0时,T1停止工作。 TR1 由软件置位或清零。 因此,可以用软件来控制定时器/计数器的启动和停止。
TF0(TCON.5):T0溢出中断请求标志,其功能与TF1类似。
TR0(TCON.4):T0操作控制位,其功能与TR1类似。
定时器/计数器的工作原理 模式 0
模式0为13位计数,由TL0的低5位(高3位未使用)和TH0的8位组成。 当TL0的低5位溢出时,将其传送到TH0。 当TH0溢出时,TCON中的TF0标志被置位,并向CPU发出中断请求。
定时器模式下:N=t/Tcy
初始计数值的计算公式为:X=213-N。
定时器的初始值也可以通过计数值的直接求补来获得。 在计数模式下,计数脉冲是T0引脚上的外部脉冲。
门控位GATE有一个特殊的作用。 当GATE=0时,或门反转后输出为1。 此时只有TR0控制与门的开启。 当与门输出1时,控制开关打开,开始计数; 当GATE=1时,外部中断引脚信号控制或门的输出。 此时与门的开启由外部中断引脚信号和TR0控制。 当TR0=1时,外部中断引脚信号引脚高电平开始计数,外部中断引脚信号引脚低电平停止计数。 该方法常用于测量外部中断引脚上正脉冲的宽度。
方式一
模式1的计数位数为16位,TL0为低8位,TH0为高8位,组成16位加1计数器。
[外部链接图像传输失败。 源站可能有防盗链机制。 建议保存图片直接上传(img-kQ5JkjD9-75)(images/image-213224.png)]
计数个数与计数初始值的关系为:X=216-N
方式2
模式2是8位计数模式,自动重新加载初始值。
[外部链接图像传输失败。 源站可能有防盗链机制。 建议保存图片直接上传(img-efF9sJMV-75)(images/image-236303.png)]
计数个数与计数初始值的关系为:X=28-N
工作模式2特别适合用作更精确的脉冲信号发生器。
方式3
模式3仅适用于定时器/计数器T0。 当定时器T1处于模式3时,相当于TR1=0,停止计数。
[外部链接图像传输失败。 源站可能有防盗链机制。 建议保存图片直接上传(img-X6iHbZXY-76)(images/image-255725.png)]
工作模式3将T0分为两个独立的8位计数器TL0和TH0。
使用定时器时应该做什么
初始化程序应完成以下工作:
中断源符号名称 中断原因中断号
INT0
外部中断0
P3.2引脚低电平或下降沿信号
T0
定时器0中断
定时器/计数器0计数回0并溢出
INT1
外部中断1
P3.3引脚低电平或下降沿信号
T1
定时器1中断
定时器/计数器1计数回0并溢出
TI/RI
串口中断
串行通信完成一帧数据的发送或接收并产生中断。
计数器初值驱动定时器0中断计算示例
/*
实验现象:第一个LED灯闪烁
*/
#include "reg52.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit LED = P2^0; // 定义P20口为LED
// 定时器0初始化
void Timer0Init() {
TMOD |= 0x01; // 选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0 = 0xFC; // 给定时器赋初值,定时1ms
TL0 = 0x18;
ET0 = 1; // 打开定时器0中断允许
EA = 1; // 打开总中断
TR0 = 1; // 打开定时器
}
void main() {
Timer0Init();
while(1);
}
void Timer0() interrupt 1 {
static u16 i;
TH0 = 0xFC; // 给定时器赋初值,定时1ms
TL0 = 0x18;
i++;
if (i == 1000) { // 1s
i = 0;
LED = ~LED;
}
}
定时器1中断示例
/*
实验现象:数码管依次显示0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F
*/
#include "reg52.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;
u8 code smgduan[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //显示0~F的值
// 定时器1初始化
void Timer1Init() {
TMOD |= 0x01; // 选择为定时器1模式,工作方式1,仅用TR1打开启动。
TH1 = 0xFC; // 给定时器赋初值,定时1ms
TL1 = 0x18;
ET1 = 1; // 打开定时器1中断允许
EA = 1; // 打开总中断
TR1 = 1; // 打开定时器
}
void main() {
Timer1Init();
while(1);
}
void Timer1() interrupt 3 {
static u16 i, n;
TH1 = 0xFC; // 给定时器1赋初值,定时1ms
TL1 = 0x18;
if (++i == 5000) { // 1s
P0 = smgduan[n++ % 16];
i = 0;
}
}
13.串行通信计算机串行通信基础知识串行通信的基本概念
[外部链接图像传输失败。 源站可能有防盗链机制。 建议保存图片直接上传(img-ziOJgVR9-78)(images/image-259195.png)]
串行通信的特点:传输线路少,远距离传输成本低,可以使用电话网络等现成的设备,但数据传输控制比并行通信复杂。
异步通信和同步通信 1、异步通信
异步通信是指通信的发送和接收设备使用各自的时钟来控制数据的发送和接收过程。 为了协调双方的发送和接收,要求发送和接收设备的时钟尽可能一致。
[外部链接图像传输失败。 源站可能有防盗链机制。 建议保存图片直接上传(img-5IPyDWAZ-78)(images/image-233173.png)]
异步通信以字符(帧)为单位进行传输。 字符之间的间隙(时间间隔)是任意的,但每个字符中的比特是在固定的时间传输的,即字符之间不一定是整数倍的“比特间隔”关系,而是每个字符中的比特之间的距离同一字符是“位间隔”的整数倍。
异步通信的数据格式:
[外部链接图像传输失败。 源站可能有防盗链机制。 建议保存图片直接上传(img-mecpYQY6-79)(images/image-253325.png)]
异步通信的特点:不需要发送方和接收方的时钟严格一致,易于实现,设备开销低。 但每个字符需要额外2~3位作为起始位和停止位,且每帧之间有间隙,因此传输效率较低。 高的。
2. 同步通讯
在同步通信期间,必须建立对发件人时钟的直接控制,以便双方都可以实现完整的同步。 目前,传输数据的位之间的距离是“位间隔”的整数倍数,并且在传输字符之间没有差距,即,位同步关系和字符同步关系得以维持。 发送者可以通过两种方式实现发件人的同步。
[外部链接图像传输失败。 源地点可能具有抗校机制。 建议保存图像并将其直接上传(IMG-7NEKDVNM-80)(Images/Image-210090.png)]
串行通信的传输方向
[外部链接图像传输失败。 源地点可能具有抗校机制。 建议保存图像并将其直接上传(img-xcnjgryy-81)(Images/Image-206955.png)]
串行通信中的常见错误检查1.均等检查
发送数据时,尾随1位数据位是奇偶校验位(1或0)。 在奇特的奇偶校验中,数据中“ 1” s的总和“ 1”的数量应该是奇数数。 甚至奇怪的是,数据中“ 1” s的总和“ 1”的数量应该是一个奇数。 数字的总和应该是偶数数字。 接收字符时,检查“ 1” s的数量。 如果发现任何不一致,则意味着在数据传输过程中发生错误。
2.代码和验证
代码和验证是当发送者总结已发送的数据块(或每个字节)以生成单字节检查字符(校验和)并将其附加到数据块的末尾时。 接收器接收数据并同时总结数据块(或每个字节),并将结果与发件人的“ checksum”进行比较。 如果匹配,则没有错误,否则认为在传输过程中会发生错误。
3.循环冗余检查
这种类型的验证是通过某些数学操作之间有效信息和检查位之间的循环验证。 它通常用于传输磁盘信息,存储区域的完整性验证等。此验证方法具有强大的误差校正功能,并广泛用于同步通信中。
传输速率
比特率是每秒发射的二进制代码的位数,单位为:每秒位(bps)。 例如,每秒传输240个字符,每个字符格式包含10位(1个启动位,1个停止位,8个数据位),然后比特率为:10位×240位/秒= 2400bps
传输距离和传输速率之间的关系
串行界面或终端可以直接传输串行信息位的最大距离与传输速率和传输线的电气特性有关。 当传输线使用不平衡的屏蔽扭曲对,每0.3m(约1英尺)使用50pf电容时,随着传输速率的增加,传输距离会降低。 当比特速率超过1000 bps时,最大传输距离会迅速下降。 例如,在9600 bps时,最大距离仅下降到76m(约250英尺)。
串行通信接口标准RS-232C接口
RS-232C是1969年由EIA(美国电子工业协会)修订的RS-232C标准。RS-232C定义了数据终端设备(DTE)和数据通信设备(DCE)之间的物理接口标准。
1.机械特征
RS-232C接口指定使用25针连接器。 明确定义了连接器的大小和每个引脚的布置位置。 (男性头)
[外部链接图像传输失败。 源地点可能具有抗校机制。 建议保存图像并将其直接上传(IMG-7YQBKQGW-82)(Images/Image-246650.png)]
2.功能特征
RS-232C标准接口的主要PIN定义
PIN号码信号名称功能信号方向
保护地线
保护性接地
2(3)
发送端
发送数据(串行输出)
DTE→DCE
3(2)
接收数据
接收数据(串行输入)
DTE←DCE
4(7)
实时传输系统
请求数据
DTE→DCE
5(8)
CTS
允许发送
DTE←DCE
6(6)
数字SR
DCE准备就绪(数据建立准备)
DTE←DCE
7(5)
地线
信号地
8(1)
二氯二苯醚
载体检测
DTE←DCE
20(4)
dtr
DTE准备就绪(数据中断准备)
DTE→DCE
22(9)
RI
铃声指示
DTE←DCE
3.过程特征
过程特征指定信号之间的时序关系,以便可以正确接收数据并正确发送数据。
[外部链接图像传输失败。 源地点可能具有抗校机制。 建议保存图像并将其直接上传(img-bgohsp9n-82)(图像/image-230745.png)]
[外部链接图像传输失败。 源地点可能具有抗校机制。 建议保存图像并将其直接上传(IMG-FJDY7SZZ-83)(Images/Image-244306.png)]
RS-232C水平和TTL级转换驱动电路
[外部链接图像传输失败。 源地点可能具有抗校机制。 建议保存图像并将其直接上传(IMG-JHTBI4GT-84)(Images/Image-241365.png)]
使用RS-232C接口的问题:1。变速箱距离短,传输速率较低
RS-232C总线标准符合电容的允许值。 使用时,传输距离通常不超过15米(线条条件良好时,它不超过数十米)。 最大传输率为20kbps。
2.有一个级别的变化
RS-232C总线标准要求发送和接收方具有共同点。 当通信距离很大时,发送方和接收方之间的地面电势差很大,并且信号接地上的地面电流和电压下降将相对较大。
3.反干扰能力不佳
RS-232C在级别转换期间使用单端输入和输出。 在传输过程中,干扰和噪声与正常信号混合。 为了提高信噪比,RS-232C总线标准必须使用相对较大的电压摆动。
RS-422A接口
[外部链接图像传输失败。 源地点可能具有抗校机制。 建议保存图像并将其直接上传(IMG-YGNTBJGA-85)(Images/Image-249799.png)]
RS-422A输出驱动程序是双端平衡驱动程序。 如果其中一条线处于逻辑“ 1”状态,则另一个线处于逻辑“ 0”状态,该状态的电压是使用单端的不平衡驱动器的两倍。 差分电路可以从地面干扰中获取有效的信号,并且差分接收器可以区分超过200mV的潜在差异。 如果在传输过程中混合干扰和噪声,则由于差分放大器的功能,干扰和噪声可以相互抵消。 因此,可以避免或大大减少地面线干扰和电磁干扰的影响。 以RS-422A的传输速率(90kbps),传输距离可以达到1200米。
RS-485接口
[外部链接图像传输失败。 源地点可能具有抗校机制。 建议保存图像并将其直接上传(IMG-PPGI61BO-86)(Images/Image-231245.png)]
RS-485是RS-422A:RS-422A的变体,用于完整双链体,而RS-485用于半双链。 RS-485是一种多递质标准,可以在通信线上使用多达32对差分驱动器/接收器。 如果将32多个设备连接到网络,也可以使用中继器。
RS-485信号传输使用两条线之间的电压来表示逻辑1和逻辑0。由于发件人需要两条传输线,因此接收器还需要两条传输线。 传输线使用差分通道,因此其干扰抑制非常好,并且由于其阻抗较低且没有接地问题,因此传输距离可以达到1200米,并且传输速率可以达到1Mbps。
RS-485是一个点对点通信接口,通常使用扭曲的对结构。 普通PC通常没有RS485接口,因此必须使用RS-232C/RS-485转换器。 对于单芯片微型计算机,您可以通过CHIP MAX485完成TTL/RS-485的级别转换。 在由计算机和单芯片单元组成的RS-485通信系统中,下部机器由单芯片微型计算机系统组成。 下部机器的工作状态以及工业场地设备的工作条件。 通过设置不同的站地址来实现系统中每个节点(包括上部机器)的识别。
80C51 80C51串行端口的串行端口的结构
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并直接上传图片(img-j3qaje8e-87)(images/image-224017.png)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
有两个物理独立的接收和发送缓冲区SBUF,它们占据了相同地址99H; 接收器是双缓冲结构; 发送缓冲区,因为发送时CPU处于活动状态,因此不会存在重叠错误。
80C51在串行端口的控制寄存器
SCON是一个特殊功能寄存器,用于设置工作方法,接收/发送控件以及串行端口的设置状态徽标:
少量
字节地址:98H
SM0
SM1
SM2
任
TB8
RB8
TI
RI
斯康
SM0和SM1是工作方法的选择数字。 您可以选择四种工作方法:
SM0SM1方法解释了波特率
移位寄存器
fosc/12f_ {OSC}/12fosc/12
10-位异步收发器(8位数据)
多变的
11-位异步收发器(9位)
fosc/64f_ {OSC}/64fosc/64或fosc/32f_ {OSC}/32Fosc/32
11-位异步收发器(9位)
多变的
PCON中只有一个SMOD与串行端口工作有关:
少量
字节地址:97H
SMOD
电脑控制网络
SMOD(PCON.7)波特率提高。 在串行端口方法1.方法2.方法3中,波特率与SMOD有关。 当smod = 1时,波特率会加倍。 重置时,SMOD = 0。
80C51串行端口工作方法1.方法0
当方法为0时,串行端口是同步移位寄存器的输入和输出方法。 它主要用于扩展并行输入或输出。 数据是由RXD(P3.0)引脚输入或输出的,并且同步移位脉冲由TXD(P3.1)引脚输出。 发送和接收是8位数据,低位置是第一个,高位置在后面。 波特率固定为FOSC/12。
1.方法0输出:
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并将其直接上传(img-df06ry7w-88)(images/image-236982.png)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
2.方法0输入:
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并直接上传图片(img-ebx19svv-89)(images/image-259584.png)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
两个,方法1 1
方法1是10位数据的异步通信端口。 TXD是数据发送引脚,RXD是一个数据接收引脚,图中显示了传输数据框架的格式。 其中一个开始,8个位置和1个站。
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并将其直接上传(img-6uyrll6i-90)(images/image-256078.png)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
1.方法1输出:
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并直接上传图片(img-fnmg5b5d-90)(images/image-209506.png)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
2.方法1输入:
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并直接上传图片(img-fmdshlrk-91)(images/image-231620.png)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
当软件设置为1时,接收器以所选陶工速率为16倍的RXD引脚水平。 当RXD引脚输入级别呈负跳跃时,这意味着起始位置是有效的,并且将是有效的。 它移至输入移位寄存器,并开始接收此帧的其余部分。 在接收过程中,数据从输入位移寄存器的右侧移动,然后将起始位置移至输入移位寄存器的最左侧,并且控制电路执行了最后一班。 当ri = 0和SM2 = 0(或停止位置接收为1)时,将收到数据接收到的第一个8位数据安装到接收的SBUF,第9位(停止)进入RB8,并将其设置为并设置它。 Ri = 1,从CPU中断。
三,方法2和方法3
方法2或方法3是11个数据数字的异步通信端口。 TXD发送一个用于数据的引脚,RXD是数据接收引脚。
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并直接上传图片(img-yugz9ix4-92)(images/image-247526.png)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
方法2和方法在1位开始时从3点开始,9位数据(包括1位额外的额外位,scon中的TB8,在接收时发送RB8),停止数字1位,一框数据是11个数据是11,11个数据是11位。 方法2的陶器速率固定为晶体频率的1/64或1/32。 方法3的陶器速率由计时器T1的溢出确定。
1.方法2和方法3输出
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并直接上传图片(img-vxdxlym1-92)(images/image-216175.png)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
在发送时,首先将启动位0输出到TXD引脚,然后将移位寄存器的输出位置(D0)发送到TXD引脚。 每个转移脉冲都使每个将输出位移寄存器转移到右侧的每个人,并通过TXD引脚输出。
当第一个偏移时,停止位“ 1”移至输出位移寄存器的第九位。 每个偏移都被换位,左侧移动到0。当停止位移至输出位置时,其余的左侧为0。当检测电路检测到此情况时,对最后一个控制电路进行了控制电路时间,Ti = 1设置为中断CPU请求。
2.方法2和方法3输入
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并直接上传图片(img-3gkwwwnla-93)(images/image-223797.png)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
接收时,数据将从右侧移动到输入位移寄存器中。 当启动位0移动到最左侧时,控制电路最后一次控制。 当RI = 0,SM2 = 0(或从1接收到的第9位数字)时,接收到的数据被加载到接收缓冲区SBUF和RB8(接收数据中的第9位),将RI = 1设置为方向,将方向定向,并走向它。 CPU请求中断。 如果未满足条件,则数据丢失并且没有放置RI,并且RXD引脚的负跳跃将继续。
波特速率计算
在串行通信中,双方已同意发送或接收数据。 单片机的串口可通过软件编程为四种工作模式。 模式0和模式2的波特率是固定的,而模式1和模式3的波特率是可变的。 由定时器T1的溢出决定。 率来决定。
串行端口的四种工作方法对应于三个陶工速率。 由于输入移位时钟的来源不同,各种方法的波特率计算公式也不同。
当T1用作陶工发生器时,最典型的用法是使T1工作8-位计时器方法(即方法2,而TCON的TR1 = 1来启动计时器)。 此时,溢出率取决于TH1中的计数值。
t1溢出速率= fosc/[12Å(256-th1)] T1溢流速率= f_ {osc}/[12·(256 -th1)] T1溢流速率= fosc/[12·(256-th1)]
在应用单芯片微型计算机的应用中,常用的晶体频率为:12MHz和11.0592MHz。 因此,选择的波特率是相对固定的。 常用的串口波特率及各参数之间的关系如表所示。
普通波特速率和计时器1之间的参数关系
候选工作方法波特速率/(B/S)FOSC(MHz)SMOD T1 T1
C / T工作方法初始值
方法1、3
62.5k
12
FFH
19.2k
11.0592
外佣
9600
11.0592
外佣
4800
11.0592
FAH
2400
11.0592
F4H
1200
11.0592
E8H
如何使用串行端口
在串行端口工作之前,它的初始化主要是设置波特率的计时器1.串行端口控制和中断控制。 具体步骤如下:
当串行端口工作时,应执行中断设置(编程,即IP寄存器)。
单芯片微型计算机和单芯片微型计算机的通信,点 – 点通信
硬件连接
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并直接上传图片(img-unsobqa8-94)(images/image-211905.png)]]]]]]]]]]]]]]]]]]]]]]]]]]
2.多机通信
硬件连接
由单芯片组成组成的多机器系统通常采用总线-Type主奴隶结构。 So称为主的奴隶风格,即在几台芯片机器中,一个是主机,其余的是机器。 80C51单芯片微型计算机2和方法3的串行端口方法适用于此主和子型通信结构。 当然,当使用不同的通信标准时,需要执行相应的级别转换,有时信号隔离了光电子隔离。 在实际的多机器应用系统中,RS-485串行标准总线通常用于数据传输。
[外部连锁图片失败了,源站可能具有反盗窃链机制。 建议保存图片并直接上传图片(img-y8ghs0dx-94)(images/image-228668.png)]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
司机
/*
实验现象:实现串口通信
注意事项:串口通信选择方式二、晶振频率为12,波特率为9600
*/
#include "reg52.h"
typedef unsigned char u8;
void UsartInit() {
TMOD = 0x20; // 选择为定时器1模式,工作方式2(8位自动重装定时/计数器),仅用TR1打开启动。
TH1 = 0xF9; // 设定串口波特率为9600
TL1 = 0XF9;
PCON = 0X80; // 设定串口波特率倍增
SCON = 0X50; // 选择串口工作方式1(10位异步收发器(8位数据)),允许接收
TR1 = 1; // 启动定时器1
ES = 1; // 打开串口中断
EA = 1; // 打开总中断
}
void main(){
UsartInit();
while(1);
}
void Usart() interrupt 4 {
u8 receiveData = SBUF; // 接收数据
RI = 0; // 关闭串口接收
SBUF = receiveData; // 发送数据
while(!TI);
TI = 0; // 停止发送
}