普中51单片机开发板笔记

   日期:2024-04-09     来源:网络整理    作者:佚名     移动:http://app.1688ku.com/article/726853.html      >> 违规举报
核心提示:普中51单片机开发板笔记我们实验板用共阴LED显示器,根据电路连接图显示16进制数的编码已列在下表。LED显示器工作方式有两种:静态显示方式和动态显示方式。开发板数码管电路图对于单片机可以通过芯片MAX485来完成TTL/RS-485的电平转换。

普中51单片机开发板笔记

用来定义位数据变量

例:sfr SCON = 0X98;

sbit LED = P0^2;

C51中常用到的一些预处理命令 #define

#define A P0

注意后面不用加分号

#typedef

typedef unsigned char int;

注意后面要加分号

重新定义一些常用的关键词,可以增强程序的可移植性,因为在不同的编译软件上面,C语言的数据类型的关键词的位宽是不一样的。

#ifndef…#endif

条件编译,常用于头文件的定义还有一些程序条件编译

C51基本数据类型 类型符号关键字所占位数数的表示范围

整型

(signed) int

16

-32768~32767

(signed) short

16

-32768~32767

(signed) long

32

-~

int

16

0~65535

short int

16

0~65535

long int

32

0~

实型

float

32

3.4e-38~3.4e38

double

64

1.7e-308~1.7e308

字符型

char

-128~127

char

0~255

常用的运算符

+、-、*、/(加、减、乘、除)

>、>=、 Licence ... >> 复制CID码 >> 打开破解工具 >> 粘贴CID码 >> 点击生成密钥并复制 >> 返回 Keil 软件粘贴密钥后点击Add Lic

创建工程模板

第一步、新建工程:打开Keil软件,选择Projet >> New μVision Projet... >> 选择保存路径,并命名为 >> 弹出提示后点击取消 >> 选择Atmel中的AT89C52或者AT89C51 >> 弹出提示框点击否

第二部、新建main程序,选择 File >> New >> 命名为main.c >> 在编辑区中粘贴以下代码:

#include "reg52.h"
void main() {
    while(1) {
        
    }
}

第三步、在新建工程Source Group 1上单击右键,选择Add Files to Group 'Source Group 1...,添加刚刚创建的main.c文件。

第四步、点击Build编译程序,保证程序无误。

第四步、点击Target Options...图标,点击Output选项卡,勾选Create HEX File选项,点击OK

配置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软件安装路径的环境变量,需要自己手动配置,我的环境变量配置如下:

01、点亮一个LED灯 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语句的语义是:计算表达式的值,当值为真(非0)时, 执行循环体语句。

延时函数

void delay (u16 i) { //大约延时10us
	while(i--);	
}

驱动程序


#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是右移的位数。

以上两个函数都包含在.h库函数里。

驱动程序 方法①


#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直流工作电压),多谐振荡器起振,输出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(Light Diode)显示器、液晶LCD(Liquid Crystal Display)显示器、TFT液晶显示器等。LED显示器有两种显示结构:段显示(7段、米字型等)和点阵显示(5×8、8×8点阵等)。

LED数码管根据LED的不同接法可以分为2类:共阴和共阳。

​ 使用LED显示器时,要注意区分这两种不同的接法。为了显示数字或字符,必须对数字或字符进行编码。七段数码管加上一个小数点,共计8段。因此为LED显示器提供的编码正好是一个字节。我们实验板用共阴LED显示器,根据电路连接图显示16进制数的编码已列在下表。

码值显示值码值显示的数据

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都保持锁存之前的那个状态。 驱动程序

实例一


#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译码器的使用

是一种三通道输入、八通道输出译码器,主要应用于消费类电子产品。

适用于数字电路中的 3—8 译码功能

管脚说明

名称功能说明管脚号

Y0‾\{Y0}Y0 — Y6‾\{Y6}Y6,Y7‾\{Y7}Y7

数据输出

15 — 9,7

A0A0A0 — A2A2A2

数据输入

1 — 3

E1‾\{E1}E1,E2‾\{E2}E2,E3E3E3

使能控制

4 — 6

逻辑电源

16

逻辑地

逻辑图

真值表

驱动程序


#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、独立按钮 按键介绍

轻触开关是一种电子开关,使用时,轻轻按开关按钮就可使开关接通,当松开手时,开关断开。我们使用的开关如下图:

独立按键原理

按键在闭合和断开时,触点会存在抖动现象。

硬件消抖电路

驱动程序


#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来判断是哪一个按键被按下。

方法二:

行列扫描:我们可以通过高四位全部输出低电平,低四位输出高电平。当接收到的数据,低四位不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一列有按键按下,然后再反过来,高四位输出高电平,低四位输出低电平1688批发网,然后根据接收到的高四位的值判断是那一行有按键按下,这样就能够确定是哪一个按键按下了。

矩阵按键怎么变成独立按键 驱动程序


#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 时(为低电平),存储寄存器的数据输出到总线。

特点 输出能力 应用

引脚说明 符号引脚描述

QA ~ QH

15、1 ~ 7

并行数据输出

GND

QH‘

串行数据输出

SRCLR

10

主复位(低电平)

SRCLK

11

移位寄存器时钟输入

RCLK

12

存储寄存器时钟输入

OE

13

输出有效(低电平)

SER

14

串行数据输入

VCC

16

电源

功能表 输入输出功能

SRCLK

RCLK

OE

SRCLR

SER

QH‘

Qn

×

×

×

NC

MR为低电平时仅仅影响移位寄存器。

×

×

空移位寄存器到输出寄存器。

×

×

×

清空移位寄存器,并行输出为高阻状态。

×

QG’

NC

逻辑高电平移入移位寄存器状态0,包含所有的移位寄存器状态移入, 例如,以前的状态G(内部 QG')出现在串行输出位。

×

×

NC

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_ds引脚当前电平值在移位寄存器中左移 一位,在下一个上升沿到来时移位寄存器中的所有位都会向左移一位, 同时 QH'也会串行输出移位寄存器中高位的值,这样连续进行 8 次,就可以把数组中每一个数(8 位的数)送到移位寄存器; 然后当上升沿到来时,移位寄存器的值将会被锁存到锁存器里, 并从 QA~QH 引脚输出

驱动程序


#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×8LED点阵的原理

什么是点阵

点阵简介

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);
	}		
}

实例二


#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

IT1

IE0

IT0

TCON

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,表示正在响应高优先级的中断114信息网MIP移动站,它将阻断后来所有的中断请求;另一个置1,表示正在响应低优先级中断,它将阻断后来所有的低优先级中断请求。

中断处理过程

中断响应条件

以上三条同时满足时,CPU才有可能响应中断。

使用中断,程序员需要做什么?

以外部中断0为例,主程序中需要有以下代码:

EA = 1;			//打开总中断开关
EX0 = 1;		//开外部中断0
IT0 = 0/1;		//设置外部中断的触发方式

中断服务函数:

void int0 () interrupt 0 using  1 {
	do anything that you want
}

驱动程序 外部中断0实例


#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实例


#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时,再输入一个脉冲就使计数器回零,且计数器的溢出使相应的中断标志位置1,向CPU发出中断请求(定时/计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。

可见,由溢出时计数器的值减去计数初值才是加1计数器的计数值。

51单片机定时器结构

定时/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器THx和TLx组成。TMOD是定时/计数器的工作方式寄存器,确定工作方式和功能;TCON是控制寄存器,控制T0、T1的启动和停止及设置溢出标志。

定时/计数器的控制

51单片机定时/计数器的工作由两个特殊功能寄存器控制。TMOD用于设置其工作方式;TCON用于控制其启动和中断申请。

1、工作方式寄存器TMOD

工作方式寄存器TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1。其格式如下:

字节地址:89H

GATE

C/T

M1

M0

GATE

C/T

M1

M0

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

方式1

16位定时/计数器

10

方式2

8位自动重装定时/计数器

11

方式3

T0分成两个独立的8位定时/计数器;T1此方式停止计数

2、控制寄存器TCON

TCON的低4位用于控制外部中断,已在前面介绍。TCON的高4位用于控

制定时/计数器的启动和中断申请。其格式如下:

字节地址:88H

TF1

TR1

TF0

TR0

TCON

TF1(TCON.7):T1溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1。CPU响应中断后TF1由硬件自动清0。T1工作时,CPU可随时查询TF1的状态。所以,TF1可用作查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0的效果一样。

TR1(TCON.6):T1运行控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。

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

方式1的计数位数是16位,由TL0作为低8位,TH0作为高8位,组成了16位加1计数器 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--75)(images/image-213224.png)]

计数个数与计数初值的关系为:X = 216-N

方式2

方式2为自动重装初值的8位计数方式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--75)(images/image-236303.png)]

计数个数与计数初值的关系为:X = 28-N

工作方式2特别适合于用作较精确的脉冲信号发生器。

方式3

方式3只适用于定时/计数器T0,定时器T1处于方式3时相当于TR1=0,停止计数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--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中断实例


#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中断实例


#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--78)(images/image-259195.png)]

​ 串行通信的特点:传输线少,长距离传送时成本低led静态显示和动态显示,且可以利用电话网等现成的设备,但数据的传送控制比并行通信复杂。

异步通信与同步通信 1、异步通信

​ 异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--78)(images/image-233173.png)]

​ 异步通信是以字符(构成的帧)为单位进行传输,字符与字符之间的间隙(时间间隔)是任意的,但每个字符中的各位是以固定的时间传送的,即字符之间不一定有“位间隔”的整数倍的关系,但同一字符内的各位之间的距离均为“位间隔”的整数倍。

异步通信的数据格式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--79)(images/image-253325.png)]

​ 异步通信的特点:不要求收发双方时钟的严格一致,实现容易,设备开销较小,但每个字符要附加2~3位用于起止位,各帧之间还有间隔,因此传输效率不高。

2、同步通信

​ 同步通信时要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的字符间不留间隙,即保持位同步关系,也保持字符同步关系。发送方对接收方的同步可以通过两种方法实现。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--80)(images/image-210090.png)]

串行通信的传输方向

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--81)(images/image-206955.png)]

串行通信常见的错误校验 1、奇偶校验

​ 在发送数据时,数据位尾随的1位为奇偶校验位(1或0)。奇校验时,数据中“1”的个数与校验位“1”的个数之和应为奇数;偶校验时,数据中“1”的个数与校验位“1”的个数之和应为偶数。接收字符时,对“1”的个数进行校验,若发现不一致,则说明传输数据过程中出现了差错。

2、代码和校验

​ 代码和校验是发送方将所发数据块求和(或各字节异或),产生一个字节的校验字符(校验和)附加到数据块末尾。接收方接收数据同时对数据块(除校验字节外)求和(或各字节异或),将所得的结果与发送方的“校验和”进行比较,相符则无差错,否则即认为传送过程中出现了差错。

3、循环冗余校验

​ 这种校验是通过某种数学运算实现有效信息与校验位之间的循环校验,常用于对磁盘信息的传输、存储区的完整性校验等。这种校验方法纠错能力强,广泛应用于同步通信中。

传输速率

​ 比特率是每秒钟传输二进制代码的位数,单位是:位/秒(bps)。如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位、1个停止位、8个数据位),这时的比特率为:10位×240个/秒 = 2400 bps

传输距离与传输速率的关系

​ 串行接口或终端直接传送串行信息位流的最大距离与传输速率及传输线的电气特性有关。当传输线使用每0.3m(约1英尺)有50PF电容的非平衡屏蔽双绞线时,传输距离随传输速率的增加而减小。当比特率超过1000 bps 时,最大传输距离迅速下降,如9600 bps 时最大距离下降到只有76m(约250英尺)。

串行通信接口标准 RS-232C接口

​ RS-232C是EIA(美国电子工业协会)1969年修订RS-232C标准。RS-232C定义了数据终端设备(DTE)与数据通信设备(DCE)之间的物理接口标准。

1、机械特性

​ RS-232C接口规定使用25针连接器,连接器的尺寸及每个插针的排 列位置都有明确的定义。(阳头)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--82)(images/image-246650.png)]

2、功能特性

​ RS-232C标准接口主要引脚定义

插针序号信号名称功能信号方向

PGND

保护接地

2(3)

TXD

发送数据(串行输出)

DTE→DCE

3(2)

RXD

接收数据(串行输入)

DTE←DCE

4(7)

RTS

请求数据

DTE→DCE

5(8)

CTS

允许发送

DTE←DCE

6(6)

DSR

DCE就绪(数据建立就绪)

DTE←DCE

7(5)

SGND

信号接地

8(1)

DCD

载波检测

DTE←DCE

20(4)

DTR

DTE就绪(数据中断准备就绪)

DTE→DCE

22(9)

RI

振铃指示

DTE←DCE

3、过程特性

​ 过程特性规定了信号之间的时序关系,以便正确地接收和发送数据 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--82)(images/image-230745.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--83)(images/image-244306.png)]

​ RS-232C电平与TTL电平转换驱动电路

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--84)(images/image-241365.png)]

采用RS-232C接口存在的问题 1、传输距离短,传输速率低

​ RS-232C总线标准受电容允许值的约束,使用时传输距离一般不要超过15米(线路条件好时也不超过几十米)。最高传送速率为20Kbps。

2、有电平偏移

​ RS-232C总线标准要求收发双方共地。通信距离较大时,收发双方的地电位差别较大,在信号地上将有比较大的地电流并产生压降。

3、抗干扰能力差

​ RS-232C在电平转换时采用单端输入输出,在传输过程中当干扰和噪声混在正常的信号中。为了提高信噪比,RS-232C总线标准不得不采用比较大的电压摆幅。

RS-422A接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--85)(images/image-249799.png)]

​ RS-422A输出驱动器为双端平衡驱动器。如果其中一条线为逻辑“1”状态,另一条线就为逻辑“0”,比采用单端不平衡驱动对电压的放大倍数大一倍。差分电路能从地线干扰中拾取有效信号,差分接收器可以分辨200mV以上电位差。若传输过程中混入了干扰和噪声,由于差分放大器的作用,可使干扰和噪声相互抵消。因此可以避免或大大减弱地线干扰和电磁干扰的影响。RS-422A传输速率(90Kbps)时,传输距离可达1200米。

RS-485接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--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转换器。对于单片机可以通过芯片MAX485来完成TTL/RS-485的电平转换。在计算机和单片机组成的RS-485通信系统中普中51单片机开发板笔记,下位机由单片机系统组成,上位机为普通的PC机,负责监视下位机的运行状态,并对其状态信息进行集中处理,以图文方式显示下位机的工作状态以及工业现场被控设备的工作状况。系统中各节点(包括上位机)的识别是通过设置不同的站地址来实现的。

80C51的串行口 80C51串行口的结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--87)(images/image-224017.png)]

​ 有两个物理上独立的接收、发送缓冲器SBUF,它们占用同一地址99H ;接收器是双缓冲结构 ;发送缓冲器,因为发送时CPU是主动的,不会产生重叠错误。

80C51串行口的控制寄存器

SCON 是一个特殊功能寄存器,用以设定串行口的工作方式、接收/发送控制以及设置状态标志:

字节地址:98H

SM0

SM1

SM2

REN

TB8

RB8

TI

RI

SCON

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

PCON

SMOD(PCON.7) 波特率倍增位。在串行口方式1、方式2、方式3时,波特率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0。

80C51串行口的工作方式 一、方式0

​ 方式0时,串行口为同步移位寄存器的输入输出方式。主要用于扩展并行输入或输出口。数据由RXD(P3.0)引脚输入或输出,同步移位脉冲由TXD(P3.1)引脚输出。发送和接收均为8位数据,低位在先,高位在后。波特率固定为fosc/12。

1、方式0输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--88)(images/image-236982.png)]

2、方式0输入:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--89)(images/image-259584.png)]

二、方式1

​ 方式1是10位数据的异步通信口。TXD为数据发送引脚,RXD为数据接收引脚,传送一帧数据的格式如图所示。其中1位起始位,8位数据位,1位停止位。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--90)(images/image-256078.png)]

1、方式1输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--90)(images/image-209506.png)]

2、方式1输入:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--91)(images/image-231620.png)]

​ 用软件置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为数据接收引脚 。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--92)(images/image-247526.png)]

​ 方式2和方式3时起始位1位,数据9位(含1位附加的第9位,发送时为SCON中的TB8,接收时为RB8),停止位1位,一帧数据为11位。方式2的波特率固定为晶振频率的1/64或1/32,方式3的波特率由定时器T1的溢出率决定。

1、方式2和方式3输出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--92)(images/image-216175.png)]

​ 发送开始时,先把起始位0输出到TXD引脚,然后发送移位寄存器的输出位(D0)到TXD引脚。每一个移位脉冲都使输出移位寄存器的各位右移一位,并由TXD引脚输出。

​ 第一次移位时,停止位“1”移入输出移位寄存器的第9位上 ,以后每次移位,左边都移入0。当停止位移至输出位时,左边其余位全为0,检测电路检测到这一条件时,使控制电路进行最后一次移位,并置TI=1,向CPU请求中断。

2、方式2和方式3输入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--93)(images/image-223797.png)]

​ 接收时,数据从右边移入输入移位寄存器,在起始位0移到最左边时,控制电路进行最后一次移位。当RI=0,且SM2=0(或接收到的第9位数据为1)时,接收到的数据装入接收缓冲器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

C / T工作方式初值

方式1、3

62.5k

12

FFH

19.2k

11.0592

FDH

9600

11.0592

FDH

4800

11.0592

FAH

2400

11.0592

F4H

1200

11.0592

E8H

串口如何使用

串行口工作之前,应对其进行初始化,主要是设置产生波特率的定时器1、串行口控制和中断控制。具体步骤如下:

串行口在中断方式工作时,要进行中断设置(编程IE、IP寄存器)。

单片机与单片机的通信 一、点对点的通信

硬件连接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--94)(images/image-211905.png)]

二、多机通信

硬件连接

​ 单片机构成的多机系统常采用总线型主从式结构。所谓主从式,即在数个单片机中,有一个是主机,其余的是从机,从机要服从主机的调度、支配。80C51单片机的串行口方式2和方式3适于这种主从式的通信结构。当然采用不同的通信标准时,还需进行相应的电平转换,有时还要对信号进行光电隔离。在实际的多机应用系统中,常采用RS-485串行标准总线进行数据传输。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img--94)(images/image-228668.png)]

驱动程序


#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;                 // 停止发送
}

【本文来源于互联网转载,如侵犯您的权益或不适传播,请邮件通知我们删除】

免责声明:普中51单片机开发板笔记来源于互联网,如有侵权请通知我们删除netprivacy@qq.com
 
 
更多>同类行业
0相关评论

推荐图文
最新发布
网站首页  |  网站地图  |  网站留言  |  RSS订阅  |  违规举报  |  陇ICP备19001095号