51单片机主要使用的函数
定时器&中断
- 定时器
- Timer0
- Timer1
- 定时模式
- 模式0:13位定时/计数器
- 模式1:16位定时/计数器
- 模式2:8位自动重载/定时计数器
- 模式3:仅限定时器0,Timer0分为两个8位计数器
- 中断
- 外部中断0,使用中断号0
- 定时中断0,使用中断号1
- 外部中断1,使用中断号2
- 定时中断1,使用中断号3
- 串口中断
计算定时时间公式
其中X为定时器初始计数值(填装进Tlx,Thx寄存器), 为晶振频率
c
// [email protected]
void Timer0Init()
{
EA = 0;
TMOD &= 0xF0;
TMOD |= 0x01; // 设定定时模式1
// 计算公式:(2^16 - X) * 12 / 晶振频率 = 定时时间(us)
TL0 = (65536 - 922) * 256;
TH0 = (65536 - 922) / 256;
TF0 = 0;
TR0 = 0;
ET0 = 1;
TR0 = 1;
EA = 1;
}
// 外部中断0
void EX0Init()
{
// 中断允许寄存器IE
EX0 = 1; // 开启0号外部中断
// 控制寄存器TCON
IT0 = 1; // 设置外部中断触发方式. // 0-低电平触发 // 1-负跳变触发
EA = 1; // 开启总中断
}
void EX0Interrupt() interrupt 0
{
}
void timer0Interrupt() interrupt 1
{
TF0 = 0;
TL0 = (65536 - 922) * 256;
TH0 = (65536 - 922) / 256;
}
写内部FLASH
STC89C52/AT89C52内部FLASH扇区地址:
第一扇区 | 第二扇区 | 第三扇区 | 第四扇区 |
---|---|---|---|
2000h~21FFh | 2200h~23FFh | 2400h~25FFh | 2600h~27FFh |
第五扇区 | 第六扇区 | 第七扇区 | 第八扇区 |
---|---|---|---|
2800h~29FFh | 2A00h~2BFFh | 2C00h~2DFFh | 2E00h~2FFFh |
- 操作模式
- 0x00: 空闲
- 0x01: 读出
- 0x02: 写入
- 0x03: 擦除
- 操作流程:
- 关闭全局定时器是为了确保连续往ISP_TRIG寄存器存入0x46和0xB9,才能使命令生效
- 推出ISP模式就是把寄存器ISP_CONTR、ISP_CMD、ISP_TRIG清空
c
#include <reg52.h>
#include <intrins.h>
sfr ISP_DATA = 0xe2;
sfr ISP_ADDRH = 0xe3;
sfr ISP_ADDRL = 0xe4;
sfr ISP_CMD = 0xe5;
sfr ISP_TRIG = 0xe6;
sfr ISP_CONTR = 0xe7;
/* -------------------------------------------------------------------------- */
/* 关闭ISP/IAP操作 */
/* -------------------------------------------------------------------------- */
void Q0()
{
ISP_CONTR = 0; // 关闭IAP功能
ISP_CMD = 0; // 待机模式,无ISP操作
ISP_TRIG = 0; // 关闭IAP功能, 清与ISP有关的特殊功能寄存器
EA = 1;
}
/* -------------------------------------------------------------------------- */
/* 擦除某一扇区(每个扇区512字节) */
/* -------------------------------------------------------------------------- */
void clearSector(unsigned int addr)
{
// 打开 IAP 功能(ISP_CONTR.7)=1:允许编程改变Flash, 设置Flash操作等待时间
// 0x83(晶振<5M) 0x82(晶振<10M) 0x81(晶振<20M) 0x80(晶振<40M)
ISP_CONTR = 0x81;
ISP_CMD = 0x03; // 用户可以对"Data Flash/EEPROM区"进行扇区擦除
ISP_ADDRL = addr; // ISP/IAP操作时的地址寄存器低八位,
ISP_ADDRH = addr >> 8; // ISP/IAP操作时的地址寄存器高八位。
EA = 0; //
ISP_TRIG = 0x46; // 在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,
ISP_TRIG = 0xB9; // 再写入B9h,ISP/IAP命令才会生效。
_nop_();
Q0(); // 关闭ISP/IAP
}
/* -------------------------------------------------------------------------- */
/* 写一字节 */
/* -------------------------------------------------------------------------- */
void writeByte(unsigned int addr, unsigned char dat)
{
ISP_CONTR = 0x81;
ISP_CMD = 0x02; // 用户可以对"Data Flash/EEPROM区"进行字节编程
ISP_ADDRL = addr;
ISP_ADDRH = addr >> 8;
ISP_DATA = dat; // 数据进ISP_DATA
EA = 0;
ISP_TRIG = 0x46;
ISP_TRIG = 0xB9;
_nop_();
Q0(); // 关闭ISP/IAP
}
/* -------------------------------------------------------------------------- */
/* 读一字节 */
/* -------------------------------------------------------------------------- */
unsigned char readByte(unsigned int addr)
{
unsigned char dat;
ISP_CONTR = 0x81;
ISP_CMD = 0x01; // 用户可以对"Data Flash/EEPROM区"进行字节读
ISP_ADDRL = addr;
ISP_ADDRH = addr >> 8;
EA = 0;
ISP_TRIG = 0x46;
ISP_TRIG = 0xB9;
_nop_();
dat = ISP_DATA; // 取出数据
Q0(); // 关闭ISP/IAP
return dat;
}
void main(){
//写数据之前需要先擦除
clearSector(0x2000);
writeByte(0x2000, 1);
}
驱动数码管
数码管有共阴和共阳的类型,引脚分布从左到右一般对应的是从最上面的灯开始,顺时针数再到中间的灯,最后的是右下角的点。转换成程序来中对应的位为hgfedcba,从高到低排列
数码管结构及引脚如下:
### a
# # f b
### g
# # e c
### . d h
因此以共阳极的数码管为例,驱动数字为1时,应往引脚传输的电平为:11111001,对应十六进制为0xF9
c
#include <reg51.h>
typedef unsigned char u8;
typedef unsigned int u32;
u8 LEDNum[10] = {0xc0, 0xf9, 0xa4, 0xb0, // 数码管显示值0-F对应的段码值//
0x99, 0x92, 0x82, 0xf8,
0x80, 0x90};
void SoftDelay(u32 time)
{
while (time--)
;
}
void main()
{
u8 cursor = 0;
while (1)
{
SoftDelay(0xabcd);
cursor++;
cursor %= 10;
P0 = LEDNum[cursor];
}
}
To Be Continued.