单片机
- 单片机:一种将中央处理器(CPU)、存储器、输入/输出接口等集成在一个芯片上的微型计算机。
- 单片机的特点:体积小、价格便宜、易于编程。
- 51单片机:8051单片机,指1980年由Intel公司推出的一种8位微控制器系列,现在更多的指实现了8051指令集(单片机的“语言”)的一系列单片机。
51单片机-STC89C52RC
- STC89C52RC:51单片机的型号是STC89C52RC-40I-LOFP44,内部同样采用了8051指令集。
- 单片机命令规则:
-
单片机分装类型:单片机的外形尺寸和材质。
- LQFP:Low-profile Quad Flat Package :
- PDIP: Plastic Dual In-line Package :
- 引脚分类:电源引脚、复位引脚、时钟引脚、通用输入输出引脚-GPIO。
闪烁LED
代码实现:
#include <STC89C5xRC.H>
#include <INTRINS.H>
// 延时函数 led灯变换太快,肉眼观察不到,使用延时函数
void Delay500ms(void) {
unsigned char data i, j, k;
_nop_();
_nop_();
i = 22;
j = 3;
k = 227;
do {
do {
while (--k);
} while (--j);
} while (--i);
}
void main() {
while (1) {
// 对P00灯的状态取反,实现闪烁
P00 = ~P00;
Delay500ms();
}
}
LED流水灯(来回)
#include <STC89C5xRC.H>
#include <INTRINS.H>
// 自定义数据类型 起别名
#define unsigned char u16
#define unsigned char u8
// 延时函数
void Delay_1MS(u16 count) {
unsigned char data i, j;
while (count > 0) {
count--;
_nop_();
i = 2;
j = 199;
do {
while (--j);
} while (--i);
}
}
// 流水灯-左右来回
void main() {
u8 tmp = 0x01;
// 定义流水灯开始方向
u8 driection = 1; // 向左
while (1) {
// 对 tmp 取反刚好就是 P0 的十六进制值
P0 = ~tmp;
Delay_1MS(100);
if (driection) {
tmp <<= 1;
// 按位与 判断最高位是否为1 ,为1 代表流水灯到最左边,
// 需要改变方向往回走
if (tmp & 0x80) {
driection = 0;
}
} else { // 向右走
tmp >>= 1;
// 按位与 判断是否到最右边
if (tmp & 0x01) { // 改变方向
driection = 1;
}
}
}
}
数码管
- 数码管原理:
- 数码管显示数字:动态扫描,每个LED灯亮灭的过程十分短暂,肉眼观察不到,视觉上体现出数码管不会灭。
数码管静态显示
- 数码管显示:阴极控制显示的位置,阳极控制显示的数字。
- 74HC138译码器:是一种三线到八线的译码器,将3位二进制输入转换为8个独立的输出信号。
- 工作原理:由三位二进制控制输入,8个独立输出信息,输出信号为低电平时,正常工作,高电平时不起作用。
- 74HC245N驱动器
- 51单片机高电平的驱动能力很微弱,不能点亮数码管,使用74HC145N作为驱动芯片。
- 工作原理:
数码管整体原理图:
- 位选:确定数码管的显示位置。
- 段选:确定数码管的显示内容。
- 位选:位选通过74HC138芯片的P13、P14、P15引脚控制。0~7 代表哪个位置的数码管。
- 段选:段选通过74HC245N驱动器控制。
- P36引脚控制数码管的输出使能。
- 代码实现:
#include <STC89C5xRC.H>
#define SMG_EN P36
typedef unsigned char u8;
// 数字0-9的编码
static u8 s_digit_codes[10] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
/**
* @brief 内部方法,让数码管某一位显示特定数字
*
* @param dig 片选, 从左到右[0-7]
* @param num 显示想要的数字编码
*/
void DigitalTube_DisplaySingle(u8 dig, u8 num) {
P0 = 0x00;
// 位选
dig <<= 3;
P1 &= 0xC7;
P1 |= dig;
// 段选
P0 = num;
}
void main () {
SMG_EN = 0;
DigitalTube_DisplaySingle(1, s_digit_codes[8]);
while(1);
}
数码管动态显示
- 显示8位以内的任意整数,靠右显示。
实现代码;
#include <STC89C5xRC.H>
#include <INTRINS.H>
#define SMG_EN P36
typedef unsigned char u8;
typedef unsigned char u16;
typedef unsigned long u32;
static codes[10] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
// 数码管显示缓存 存放需要显示的数据
static buffer[8];
// 延时1s
void Delay1ms(u16 count) {
u8 i, j;
while (count > 0) {
count--;
_nop_();
i = 2;
j = 199;
do {
while (--j);
} while (--i);
}
}
// 数码管显示内容
void DigitalTube_DisplayNum(u32 num) {
// 将数字每位存储到缓存中
u8 i;
// 将缓存中的数据清零,避免影响到下一个不同位数数字的显示
for (i = 0; i < 8; i++) {
buffer[i] = 0x00;
}
// num = 0;
if (num == 0) {
buffer[7] = codes[0];
return;
}
i = 7;
while (num > 0) {
buffer[i] = codes[num % 10];
num /= 10;
i--;
}
}
/**
* 方法:让数码管显示特定的数字
*
* position 位选
*
* code_num 段选
*
*/
static void DigitalTube_DisplaySingle(u8 position, u8 code_num) {
// 清除上一次的显示
P0 = 0x00;
// 位选
position <<= 3;
P1 &= 0xC7;
P1 |= position;
// 段选
P0 = code_num;
}
// 遍历数码管缓存中的数据
void DigitalTube_Refresh() {
u8 i;
for (i = 0; i < 8; i++) {
DigitalTube_DisplaySingle(i, buffer[i]);
Delay1ms(1);
}
}
void main() {
SMG_EN = 0;
DigitalTube_DisplayNum(8593);
while(1) {
DigitalTube_Refresh();
}
}
// Int_DigitalTube.h
#ifndef __INT_DIGITALTUBE_H__
#define __INT_DIGITALTUBE_H__
#define SMG_EN P36
#define LED_EN P34
#include "Com_Util.h"
void Int_DigitalTube_Init();
void Int_DigitalTube_DisplayNum(u32 num);
void Int_DigitalTube_Refresh();
#endif /* __INT_DIGITALTUBE_H__ */
// Int_DigitalTube.c
#include "Int_DigitalTube.h"
#include <STC89C5xRC.H>
// 锟斤拷锟斤拷0-9锟侥憋拷锟斤拷
static u8 s_codes[10] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
static u8 s_buffer[8];
void Int_DigitalTube_Init()
{
SMG_EN = 0;
LED_EN = 0;
}
/**
* @brief 锟节诧拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟侥骋晃伙拷锟绞撅拷囟锟斤拷锟斤拷锟�
*
* @param position 片选, 锟斤拷锟斤拷锟斤拷[0-7]
* @param num_code 锟斤拷示锟斤拷要锟斤拷锟斤拷锟街憋拷锟斤拷
*/
static void Int_DigitalTube_DisplaySingle(u8 position, u8 num_code)
{
P0 = 0x00;
// 位选锟斤拷P15 P14 P13
position <<= 3;
P1 &= 0xC7;
P1 |= position;
// 锟斤拷选锟斤拷P0
P0 = num_code;
}
void Int_DigitalTube_DisplayNum(u32 num)
{
u8 i;
for (i = 0; i < 8; i++) {
s_buffer[i] = 0x00;
}
if (num == 0) {
s_buffer[7] = s_codes[0];
return;
}
i = 7;
while (num > 0) {
s_buffer[i] = s_codes[num % 10];
num /= 10;
i--;
}
}
void Int_DigitalTube_Refresh()
{
u8 i;
for (i = 0; i < 8; i++) {
Int_DigitalTube_DisplaySingle(i, s_buffer[i]);
Com_Util_Delay1ms(1);
}
}
// main.c
#include "Int_DigitalTube.h"
void main()
{
Int_DigitalTube_Init();
Int_DigitalTube_DisplayNum(855678);
while (1) {
Int_DigitalTube_Refresh();
}
}