STC89C52RC
芯片手册
原理图
扩展版原理图
LED灯
点亮LED灯
# include <STC89C5xRC.H>
void main(){
//将LED连接的P00端口设置为0
P00 =0;
while(1);
}
LED灯闪烁
#include <STC89C5xRC.H> // 包含STC89C52RC系列单片机寄存器定义头文件
#include <INTRINS.H> // 包含内部函数库(提供_nop_()空指令)
/* 类型重定义(增强可读性)*/
typedef unsigned char u8; // 定义无符号8位数据类型(范围0~255)
typedef unsigned int u16; // 定义无符号16位数据类型(范围0~65535)
void main()
{
// 变量初始化
u8 temp = 0x01; // 初始化LED位置(二进制00000001,对应最右侧LED)
P46 = 0; // 关闭蜂鸣器(硬件设计缺陷,P4.6低电平关闭蜂鸣器)
// 如果不设置,上电时可能产生噪音
while (1) // 主循环(单片机程序必须包含无限循环)
{
/* LED显示控制 */
P0 = ~temp; // 输出到P0口控制LED:
// - 取反操作是因为采用共阳接法(端口输出0时LED亮)
// - 例如temp=0x01(00000001),取反后=0xFE(11111110),
// 即P0.0输出0,对应LED点亮
/* 更新LED位置 */
temp <<= 1; // 左移一位,实现LED流水效果
// 例如:0x01→0x02→0x04→...→0x80
/* 循环检测 */
if (temp == 0) // 当左移超出8位时(0x80<<1会变成0x00)
{
temp = 0x01; // 重新从最右侧开始
}
/* 延时控制流水速度 */
Delayms(100); // 延时100ms(控制LED移动速度)
}
}
跑马灯
#include <STC89C5xRC.H> // 包含STC89C52RC系列单片机头文件
#include <INTRINS.H> // 包含 intrinsics 函数(如_nop_)
typedef unsigned char u8; // 定义无符号8位数据类型(0~255)
typedef unsigned int u16; // 定义无符号16位数据类型(0~65535)
// 函数声明
void Delayms(u16 count); // 毫秒级延时函数声明
void main()
{
// 变量初始化
u8 temp = 0x01; // 初始灯位(00000001,最右侧LED亮)
bit is_left = 1; // 方向标志(1=左移,0=右移)
while (1) // 主循环
{
P0 = ~temp; // 输出到P0口(取反因为LED共阳接法)
// 根据移动方向更新灯位
if (is_left) {
temp <<= 1; // 左移一位(LED向左移动)
} else {
temp >>= 1; // 右移一位(LED向右移动)
}
// 检测边界条件并改变方向
if (temp == 0x80) { // 当移动到最左端(10000000)
is_left = 0; // 改为右移方向
}
if (temp == 0x01) { // 当移动到最右端(00000001)
is_left = 1; // 改为左移方向
}
Delayms(100); // 延时100ms控制移动速度
}
}
使用定时器中断设计的跑马灯
#include "Int_FlowLed.h"
static void Int_FlowLed_Refresh(){
static u8 count=100;
static u8 temp =0x01;
static bit is_left =1;
if(count==100){
P0=~temp;
if(is_left==1){
temp<<=1;
}
if(is_left==0){
temp>>=1;
}
if(temp==0x01){
is_left=1;
}
if(temp==0x80){
is_left=0;
}
}
count--;
if (count==0)
{
count=100;
}
}
void Int_Flowed_Init(){
P34=1;
Dri_Timer0_init();
Dri_Timer0_RegisterCallback(Int_FlowLed_Refresh);
}
#ifndef __INT_FLOWL_H__
#define __INT_FLOWL_H__
#include "..\Com\Com_Util.h"
#include "..\Dir\Dri_ Timer0.h"
void Int_Flowed_Init();
#endif
数码管
数码管初始化、位选、管选、显示数字、刷新
#ifndef __INT_DIGITALTUBE_H__
#define __INT_DIGITALTUBE_H__
#include "..\Com\Com_Util.h"
/**
* @brief 数码管初始化
*/
void Int_DigitalTube_Init();
/**
* @brief 将指定的整数设置到数码管显示缓存中(digital_buffer数组)
*
* @param number
*/
void Int_DigitalTube_setBuffer(u32 number);
/**
* @brief 数码管指定位置指定数字
*
* @param pos 位置,使用数字0~7分别表示从左边数第1到到第8个
* @param code 数字的段选信息
*/
void Int_DigitalTube_Single(u8 pos, u8 number_code);
/**
* @brief 刷新数码管
*
*/
void Int_DigitalTube_Refresh();
#include "Int_DigitalTube.h"
// 定义数组,保存每个数字的段选信息
static u8 s_number_codes[10] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
// 定义数组,8个元素,对应数码管8个位置; 每个元素存储数字的段选信息
static u8 s_digital_buffer[8];
/**
* @brief 将指定的整数设置到数码管显示缓存中(s_digital_buffer数组)
*
* @param number
*/
void Int_DigitalTube_setBuffer(u32 number)
{
u8 i;
// 1. 清空之前的显示内容
for (i = 0; i < 8; i++)
{
s_digital_buffer[i] = 0x00;
}
// 2. 依次取出number中每位上的数,将其段选信息存储数组;最低位存入最后一个元素
for (i = 7;; i--)
{
// 取出当前位上的数,将其段选信息存入数组指定位置
s_digital_buffer[i] = s_number_codes[number % 10];
// 处理number,去掉最低位
number /= 10;
// 如果number变为0,说明数字已经取完,停止循环
if (number == 0 || i == 0)
{
break;
}
}
}
/**
* @brief 数码管指定位置指定数字
*
* @param pos 位置,使用数字0~7分别表示从左边数第1到到第8个
* @param code 数字的段选信息
*/
void Int_DigitalTube_Single(u8 pos, u8 number_code)
{
// 1. 位选 -------------------------------
// 1.1 pos 左移3位, 与P15、P14、P13 对齐
pos <<= 3;
// 1.2 将P1的P15、P14、P13三位置0,其他位保持不变, P1 & 0b11000111
P1 &= 0xC7;
// 1.3 将pos上的三位有效数, 赋值到 P15、P14、P13 位置上
P1 |= pos;
// 2. 段选 --------------------------------
P0 = number_code;
}
/**
* @brief 刷新数码管
*
*/
void Int_DigitalTube_Refresh()
{
// 循环0到7
u8 i;
for (i = 0; i <= 7; i++)
{
Int_DigitalTube_Single(i, s_digital_buffer[i]);
Delayms(1);
}
}
数码管显示小数,基于上面“数码管初始化、位选、管选、显示数字、刷新”的代码
/**
* @brief 将指定的整数设置到数码管显示缓存中(s_digital_buffer数组)
*
* @param number
*/
void Int_DigitalTube_setBuffer(float number)
{
u8 i;
u8 number_str_index;
bit is_dot=0;
char number_str[17];
// 1. 清空之前的显示内容
for (i = 0; i < 8; i++)
{
s_digital_buffer[i] = 0x00;
}
sprintf(number_str,"%f",number);
number_str_index = strlen(number_str)-1;
while (number_str[number_str_index]==48)
{
number_str_index--;
}
// 2. 依次取出number中每位上的数,将其段选信息存储数组;最低位存入最后一个元素
for (i = 7;; i--,number_str_index--)
{
if(number_str[number_str_index]==46){
is_dot=1;
i++;
continue;
}
if (is_dot==1)
{
s_digital_buffer[i]=s_number_codes[number_str[number_str_index]-48]+0x80;
is_dot=0;
}else{
s_digital_buffer[i]=s_number_codes[number_str[number_str_index]-48];
}
if (i == 0||number_str_index == 0)
{
break;
}
}
}
定时器实现数码管数字的现时
#include "Int_DigitalTube.h"
// 定义数组,保存每个数字的段选信息
static u8 s_number_codes[10] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
// 定义数组,8个元素,对应数码管8个位置; 每个元素存储数字的段选信息
static u8 s_digital_buffer[8];
/**
* @brief 数码管指定位置指定数字
*
* @param pos 位置,使用数字0~7分别表示从左边数第1到到第8个
* @param code 数字的段选信息
*/
void Int_DigitalTube_Single(u8 pos, u8 number_code)
{
// 1. 位选 -------------------------------
// 1.1 pos 左移3位, 与P15、P14、P13 对齐
pos <<= 3;
// 1.2 将P1的P15、P14、P13三位置0,其他位保持不变, P1 & 0b11000111
P1 &= 0xC7;
// 1.3 将pos上的三位有效数, 赋值到 P15、P14、P13 位置上
P1 |= pos;
// 2. 段选 --------------------------------
P0 = number_code;
}
/**
* @brief 刷新数码管
*
*/
void Int_DigitalTube_Refresh()
{
// 循环0到7
static u8 i=0;
Int_DigitalTube_Single(i, s_digital_buffer[i]);
i++;
if(i==8){
i=0;
}
}
/**
* @brief 数码管初始化
*/
void Int_DigitalTube_Init()
{
// 打开数码管开关
P36 = 0;
// 关闭流水灯
P34 = 0;
Dri_Timer0_init();
Dri_Timer0_RegisterCallback(Int_DigitalTube_Refresh);
}
/**
* @brief 将指定的整数设置到数码管显示缓存中(s_digital_buffer数组)
*
* @param number
*/
void Int_DigitalTube_setBuffer(u32 number)
{
u8 i;
// 1. 清空之前的显示内容
for (i = 0; i < 8; i++)
{
s_digital_buffer[i] = 0x00;
}
// 2. 依次取出number中每位上的数,将其段选信息存储数组;最低位存入最后一个元素
for (i = 7;; i--)
{
// 取出当前位上的数,将其段选信息存入数组指定位置
s_digital_buffer[i] = s_number_codes[number % 10];
// 处理number,去掉最低位
number /= 10;
// 如果number变为0,说明数字已经取完,停止循环
if (number == 0 || i == 0)
{
break;
}
}
}
void Int_DigitalTube_setPointBuffer(double number){
u8 i;
u8 number_str_index;
bit is_dot=0;
char number_str[17];
// 1. 清空之前的显示内容
for (i = 0; i < 8; i++)
{
s_digital_buffer[i] = 0x00;
}
sprintf(number_str,"%f",number);
number_str_index = strlen(number_str)-1;
while (number_str[number_str_index]==48)
{
number_str_index--;
}
// 2. 依次取出number中每位上的数,将其段选信息存储数组;最低位存入最后一个元素
for (i = 7;; i--,number_str_index--)
{
if(number_str[number_str_index]==46){
is_dot=1;
i++;
continue;
}
if (is_dot==1)
{
s_digital_buffer[i]=s_number_codes[number_str[number_str_index]-48]+0x80;
is_dot=0;
}else{
s_digital_buffer[i]=s_number_codes[number_str[number_str_index]-48];
}
if (i == 0||number_str_index == 0)
{
break;
}
}
}
#ifndef __INT_DIGITALTUBE_H__
#define __INT_DIGITALTUBE_H__
#include <STDIO.H>
#include <STRING.H>
#include "..\Com\Com_Util.h"
#include "..\Dir\Dri_ Timer0.h"
void Int_DigitalTube_Init();
void Int_DigitalTube_setBuffer(u32 number);
void Int_DigitalTube_setPointBuffer(double number);
#endif
独立按键
检测那个独立按键被按下
#ifndef __INK_KEY_H__
#define __INK_KEY_H__
#include "..\Com\Com_Util.h"
// 按键引脚定义(根据实际硬件连接)
#define SW1 P42 // 按键1(P4.2)
#define SW2 P43 // 按键2(P4.3)
#define SW3 P32 // 按键3(P3.2)
#define SW4 P33 // 按键4(P3.3)
bit Int_Key_IsSW1Pressed();
bit Int_Key_IsSW2Pressed();
bit Int_Key_IsSW3Pressed();
bit Int_Key_IsSW4Pressed();
#endif
# include "Int_Key.h"
bit Int_Key_IsSW1Pressed(){
if(SW1==0){
Delayms(10);
if(SW1==0){
while (SW1==0);
return 1;
}
}
return 0;
}
bit Int_Key_IsSW2Pressed()
{
if(SW2==0){
Delayms(10);
if(SW2==0){
while (SW2==0);
return 1;
}
}
return 0;
}
bit Int_Key_IsSW3Pressed()
{
if(SW3==0){
Delayms(10);
if(SW3==0){
while (SW3==0);
return 1;
}
}
return 0;
}
bit Int_Key_IsSW4Pressed()
{
if(SW4==0){
Delayms(10);
if(SW4==0){
while (SW4==0);
return 1;
}
}
return 0;
}
检测矩阵按键,那个被按下
#ifndef __INT_MATRIX_KEY__
#define __INT_MATRIX_KEY__
#include "..\Com\Com_Util.h"
u8 Int_MatrixKey_Check_Key();
#endif
# include "Int_MatrixKey.h"
static u8 s_lines[4]={0xFE,0xFD,0xFB,0xF7};
u8 Int_MatrixKey_Check_Key()
{
u8 i;
for (i = 0; i < 4; i++)
{
P2=s_lines[i];
if (P24==0)
{
Delayms(10);
while (P24==0);
return 5+i*4;
}
if (P25==0)
{
Delayms(10);
while (P25==0);
return 6+i*4;
}
if (P26==0)
{
Delayms(10);
while (P26==0);
return 7+i*4;
}
if (P27==0)
{
Delayms(10);
while (P27==0);
return 8+i*4;
}
}
return 0;
}
蜂鸣器
让蜂鸣器发出声音
#ifndef __INT_BUZZER_H__
#define __INT_BUZZER_H__
#include "..\Com\Com_Util.h"
void Int_Buzzer_Buzz(u16 ms);
#endif
#include "Int_Buzzer.h"
void Int_Buzzer_Buzz(u16 ms){
while (ms)
{
ms--;
P46=~P46;
Delayms(1);
}
P46=0;
}
让蜂鸣器发出不同大小的声音
#ifndef __INT_BUZZER_H__
#define __INT_BUZZER_H__
#include "..\Com\Com_Util.h"
void Int_Buzzer_Buzz(u16 ms);
void Int_Buzzer_BuzzLoud(u16 us);
void Int_Buzzer_BuzzLow(u16 us);
#endif
#include "Int_Buzzer.h"
void Int_Buzzer_Buzz(u16 ms){
while (ms)
{
ms--;
P46=~P46;
Delayms(1);
}
P46=0;
}
void Int_Buzzer_BuzzLoud(u16 us){
while (us)
{
us-=2;
P46=1;
Delay100us(19);
P46=0;
Delay100us(1);
}
P46=0;
}
void Int_Buzzer_BuzzLow(u16 us){
while (us)
{
us-=2;
P46=1;
Delay100us(1);
P46=0;
Delay100us(19);
}
P46=0;
}
让蜂鸣器发出不同类型的声音
#ifndef __INT_BUZZER_H__
#define __INT_BUZZER_H__
#include "..\Com\Com_Util.h"
void Int_Buzzer_BuzzMusic(u16 ms,u8 type);
#endif
#include "Int_Buzzer.h"
void Int_Buzzer_BuzzMusic(u16 ms, u8 type)
{
u16 count=0;
u8 t=0;
switch (type)
{
case 1:
t = 100000 / (2 * 400);
break;
case 2:
t = 100000 / (2 * 450);
break;
case 3:
t = 100000 / (2 *506);
break;
case 4:
t = 100000 / (2 * 540);
break;
case 5:
t = 100000 / (2 * 600);
break;
case 6:
t = 100000 / (2 * 675);
break;
case 7:
t = 100000 / (2 * 759);
break;
case 8:
t = 100000 / (2 * 800);
break;
default:t = 100000 / (2 * 1000);
break;
}
count = (ms*100)/t;
while (count)
{
count--;
P46 = ~P46;
Delayms(t);
}
P46 = 0;
}
中断
中断控制信息获取
外部中断
开启中断总开关
开启特定的外部中断
设置中断的触发方式
设置中断的优先级
设置中断服务程序
在中断结构处找到使能开关(EA),并判断其所处的寄存器能否按位寻址
设置具体开放那个中断,找到开放具体中断的控制位,判单其是否可以按位寻址
找到控制位,判断其寄存器是否可以按位寻址,设置要开启的中断的触发方式


找到功能位,判断其寄存器是否可以按位寻址,设置中断的优先级


判断中断类型,找到中编号,编写中断服务程序

#include ".\Com\Com_Util.h"
#include ".\Int\Int_Key.h"
#include ".\Int\Int_Buzzer.h"
#include ".\Int\Int_DigitalTube.h"
#include ".\Int\Int_MatrixKey.h"
void main()
{
P46=0;
EA =1;
EX0 =1;
IT0=1;
PX0=1;
IPH|=0x01;
while (1);
}
void Interrupt_program() interrupt 0{
P00 =~P00;
}
定时器中断
开启中断总开关
开启特定的中断
设置中断的触发方式
设置中断的优先级
设置中断服务程序
开启中断开关





封装的代码
#include "Dri_ Timer0.h"
static Timer_Callback s_callback[MAX_CALLBACK_COUNT]={NULL,NULL,NULL,NULL};
static u16 s_count=1000;
void Dri_Timer0_init(){
EA=1;
ET0=1;
TMOD &=0xF0;
TMOD |=0x01;
TL0=64616;
TH0=64616>>8;
IPH |=0x02;
PT0=0;
TR0=1;
}
bit Dri_Timer0_RegisterCallback(Timer_Callback cb){
u8 i;
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_callback[i]==cb)
{
return 0;
}
}
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_callback[i]==NULL)
{
s_callback[i]=cb;
return 1;
}
}
return 0;
}
bit Dri_Timer0_DeleteRegisterCallback(Timer_Callback cb){
u8 i;
for (i = 0; i < MAX_CALLBACK_COUNT; i++)
{
if (s_callback[i]==cb)
{
s_callback[i]=NULL;
return 1;
}
}
return 0;
}
void Dri_Timer0_Handler() interrupt 1{
u8 i;
TL0=64616;
TH0=64616>>8;
for (i = 0; i <MAX_CALLBACK_COUNT; i++)
{
if(s_callback[i]!=NULL){
s_callback[i]();
}
}
}
#ifndef __Dri_TIMER0_H__
#define __Dri_TIMER0_H__
#include "..\Com\Com_Util.h"
#include "STDIO.H"
#define MAX_CALLBACK_COUNT 4
typedef void (*Timer_Callback)(void);
void Dri_Timer0_init();
bit Dri_Timer0_RegisterCallback(Timer_Callback cb);
bit Dri_Timer0_DeleteRegisterCallback(Timer_Callback cb);
#endif
串口中断
工具包
延时函数,延时ms级别
#ifndef __COM_UTIL_H__
#define __COM_UTIL_H__
#include <STC89C5xRC.H>
#include <INTRINS.H>
// 类型别名
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
/**
* @brief 延时函数,指定延时多少毫秒
*
* @param count 指定多少毫秒
*/
void Delayms(u16 count);
#endif
#include "Com_Util.h"
// 延时函数,指定延时多少毫秒
void Delayms(u16 count)
{
u8 data i, j;
while (count)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j)
;
} while (--i);
count--;
}
}
延时函数,延时us级,基于延时ms级的代码
void Delay100us(u16 count){
unsigned char data i;
while (count)
{
_nop_();
i = 43;
while (--i);
count--;
}
}








3627

被折叠的 条评论
为什么被折叠?



