51单片机编程

51单片机主要使用的函数

定时器&中断

  • 定时器
    • Timer0
    • Timer1
  • 定时模式
    • 模式0:13位定时/计数器
    • 模式1:16位定时/计数器
    • 模式2:8位自动重载/定时计数器
    • 模式3:仅限定时器0,Timer0分为两个8位计数器
  • 中断
    • 外部中断0,使用中断号0
    • 定时中断0,使用中断号1
    • 外部中断1,使用中断号2
    • 定时中断1,使用中断号3
    • 串口中断

计算定时时间公式

(216X)×12fn=Time(2^{16}-X)\times \frac{12}{f_n}=Time

其中X为定时器初始计数值(填装进Tlx,Thx寄存器), fnf_n 为晶振频率

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~21FFh2200h~23FFh2400h~25FFh2600h~27FFh
第五扇区第六扇区第七扇区第八扇区
2800h~29FFh2A00h~2BFFh2C00h~2DFFh2E00h~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.
数字信号处理Matlab编程