常用的一些文件

常用的一些文件

数码管真值表

数码管真值表

unsigned char code LedChar[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E};

使用示例

功能:令普中51开发板的最右侧数码管进行16进制定时。

#include <reg52.h>

unsigned char code LedChar[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E};

unsigned char cnt = 0; // 记录T0中断次数
unsigned char sec = 0; // 记录经过的秒数

sbit addr_1 = P2 ^ 2;
sbit addr_2 = P2 ^ 3;
sbit addr_3 = P2 ^ 4;

void main()
{
    addr_1 = 0;
    addr_2 = 0;
    addr_3 = 0;

    TMOD = 0x01;
    TH0 = 0xB8;
    TL0 = 0x00;
    TR0 = 1;

    while (1)
    {
        if (TF0 == 1)
        {
            TF0 = 0;
            TH0 = 0xB8;
            TL0 = 0x00;

            P0 = ~LedChar[sec];
            cnt++;
            if (cnt >= 50)
            {
                cnt = 0;
                sec++;
                if (sec >= 16)
                {
                    sec = 0;
                }
            }
        }
    }
    return;
}

四相五线步进电机

步进电机内部结构示意图

步进电机内部结构示意图

四相五线步进电机八拍模式绕组控制顺序表

四相五线步进电机八拍模式绕组控制顺序表

步进电机控制电路

步进电机控制电路

28BYJ-48 步进电机参数表

28BYJ-48 步进电机参数表

真实减速比:1:63.684,转过一圈所需节拍数:64*63.684≈4076

步进电机节拍对应的 IO 控制代码

unsigned char code BeatCode[8] = { // 步进电机节拍对应的 IO 控制代码
    0xE, 0xC, 0xD, 0x9, 0xB, 0x3, 0x7, 0x6};

示例代码

#include <reg52.h>

unsigned char code BeatCode[8] = { // 步进电机节拍对应的 IO 控制代码
    0xE, 0xC, 0xD, 0x9, 0xB, 0x3, 0x7, 0x6};

void delay();

void main()
{
    unsigned char tmp;       // 定义一个临时变量
    unsigned char index = 0; // 定义节拍输出索引

    while (1)
    {
        tmp = P1;               // 暂存P1口
        tmp &= 0xF0;            // 清除低四位
        tmp |= BeatCode[index]; // 将节拍写入低四位
        P1 = tmp;               // 把低 4 位的节拍代码和高 4 位的原值送回 P1

        index++;       // 节拍输出索引递增
        index &= 0x07; // 到 8 归零
        delay();       // 延时 2ms,即 2ms 执行一拍
    }
}

void delay()
{
    unsigned char sec = 200;

    while (sec--)
        ;
}

配置T0中断

/*配置并启动T0即T0中断,ms为T0定时时间*/
void configTimer0(unsigned int ms)
{
    unsigned long temp = 0;

    temp = 11059200 / 12;
    temp = (temp * ms) / 1000;
    temp = 65536 - temp;
    temp = temp + 13;                  // 补偿中断响应延时造成的误差(按需调整)
    T0RH = (unsigned char)(temp >> 8); // 定时器重载值拆分为高低字节
    T0RL = (unsigned char)temp;
    TMOD &= 0xF0;
    TMOD |= 0x01;
    TH0 = T0RH;
    TL0 = T0RL;
    ET0 = 1;
    TR0 = 1;
}

串口配置函数

请输入图片描述

/*串口配置函数,baud为通信波特率*/
void configUART(unsigned int baud)
{
    SCON = 0x50;
    TMOD &= 0x0F;
    TMOD |= 0x20;
    TH1 = 256 - 11059200 / 12 / 2 / 16 / baud;
    TL1 = TH1;
    ES = 1; // 使能串口中断
    TR1 = 1;
}

LCD1602驱动代码

LCD1602.c:

// 基于普中51开发板——LCD1601驱动
#include <REG52.H>

#define LCD1602_DB P0

sbit LCD1602_RS = P2 ^ 6;
sbit LCD1602_RW = P2 ^ 5;
sbit LCD1602_EN = P2 ^ 7;

/*等待液晶准备好*/
void lcdWaitReady()
{
    unsigned char sta;

    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do
    {
        LCD1602_EN = 1;
        sta = LCD1602_DB; // 读取状态字
        LCD1602_EN = 0;
    } while (sta & 0x80); // bit_7为1时表示液晶正忙,重复检测直到其等于1为止
}
/*向LCD1602液晶写入一字节命令,cmd为待写入命令值*/
void lcdWriteCmd(unsigned char cmd)
{
    lcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_EN = 1;
    LCD1602_EN = 0;
}
/*向LCD1602液晶写入一字节命令,dat为待写入命令*/
void lcdWriteDta(unsigned char dat)
{
    lcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_EN = 1;
    LCD1602_EN = 0;
}
/*设置显示RAM起始地址,亦即光标位置,(x,y)为对应屏幕上的字符坐标*/
void lcdSetCursor(unsigned char x, unsigned char y)
{
    unsigned char addr;

    if (y == 0)
    {                    // 由输入的屏幕坐标计算显示RAM的地址
        addr = 0x00 + x; // 第一行字符地址从0x00起始
    }
    else
    {
        addr = 0x40 + x; // 第二行字符地址从0x40起始
    }
    lcdWriteCmd(addr | 0x80); // 设置RAM地址
}
/*在液晶上显示字符串,(x,y)为对应屏幕上的起始坐标,str为字符串指针,len为需显示的字符长度*/
void lcdShowStr(unsigned char x, unsigned char y, unsigned char *str, unsigned char len)
{
    lcdSetCursor(x, y); // 设置起始地址
    while (len--)
    {                        // 连续写入字符串数据
        lcdWriteDta(*str++); // 先取str指向的数据,然后str自加1
    }
}
/*区域清除,清除从(x,y)坐标起始的len个字符*/
void lcdAreaClear(unsigned char x, unsigned char y, unsigned char len)
{
    lcdSetCursor(x, y);
    while (len--)
    {
        lcdWriteDta(' ');
    }
}
/*清屏指令*/
void lcdFullClear()
{
    lcdWriteCmd(0x01);
}
/*初始化1602液晶*/
void initLCD1602()
{
    lcdWriteCmd(0x38); // 16*2显示,5*7点阵,8位数据接口
    lcdWriteCmd(0x0C); // 显示器开,光标关闭
    lcdWriteCmd(0x06); // 文字不动,地址自动+1
    lcdWriteCmd(0x01); // 清屏
}

使用示例

功能:字幕滚动

main.c:

#include <REG52.H>

bit flag500ms = 0;
unsigned char T0RH = 0;
unsigned char T0RL = 0;
unsigned char code str1[] = "Hello world! ";
unsigned char code str2[] = "I'm Liukanxi.";

void configTimer0(unsigned int ms);
extern void initLCD1602();
extern void lcdShowStr(unsigned char x, unsigned char y, unsigned char *str, unsigned char len);

void main()
{
    unsigned char i;
    unsigned char index = 0;
    unsigned char pdata bufMove1[16 + sizeof(str1) + 16];
    unsigned char pdata bufMove2[16 + sizeof(str2) + 16];

    for (i = 0; i < 16; i++)
    {
        bufMove1[i] = ' ';
        bufMove2[i] = ' ';
    }
    for (i = 16; i < 16 + sizeof(str1) - 1; i++)
    {
        bufMove1[i] = str1[i - 16];
        bufMove2[i] = str2[i - 16];
    }
    for (i = 16 + sizeof(str1) - 1; i < sizeof(bufMove1); i++)
    {
        bufMove1[i] = ' ';
        bufMove2[i] = ' ';
    }
    EA = 1;
    configTimer0(10);
    initLCD1602();

    while (1)
    {
        if (flag500ms)
        {
            flag500ms = 0;
            lcdShowStr(0, 0, bufMove1 + index, 16);
            lcdShowStr(0, 1, bufMove2 + index, 16);
            index++;
            if (index >= 16 + sizeof(str1) - 1)
                index = 0;
        }
    }
}
/*配置并启动T0即T0中断,ms为T0定时时间*/
void configTimer0(unsigned int ms)
{
    unsigned long temp = 0;

    temp = 11059200 / 12;
    temp = (temp * ms) / 1000;
    temp = 65536 - temp;
    temp = temp + 12;                  // 补偿中断响应延时造成的误差
    T0RH = (unsigned char)(temp >> 8); // 定时器重载值拆分为高低字节
    T0RL = (unsigned char)temp;
    TMOD &= 0xF0;
    TMOD |= 0x01;
    TH0 = T0RH;
    TL0 = T0RL;
    ET0 = 1;
    TR0 = 1;
}

void interruptTimer0() interrupt 1
{
    static unsigned char cnt500ms = 0;

    TH0 = T0RH;
    TL0 = T0RL;

    cnt500ms++;
    if (cnt500ms >= 50)
    {
        flag500ms = 1;
        cnt500ms = 0;
    }
}

keyboard.c

#include <REG52.H>

sbit keyIn_1 = P1 ^ 7;
sbit keyIn_2 = P1 ^ 6;
sbit keyIn_3 = P1 ^ 5;
sbit keyIn_4 = P1 ^ 4;
sbit keyOut_1 = P1 ^ 3;
sbit keyOut_2 = P1 ^ 2;
sbit keyOut_3 = P1 ^ 1;
sbit keyOut_4 = P1 ^ 0;

unsigned char code keyCodeMap[4][4] = {
    {0x01, 0x02, 0x03, 0x0A},
    {0x04, 0x05, 0x06, 0x0B},
    {0x07, 0x08, 0x09, 0x0C},
    {0x0E, 0x00, 0x0F, 0x0D}};

unsigned char pdata keySta[4][4] = {
    {1, 1, 1, 1},
    {1, 1, 1, 1},
    {1, 1, 1, 1},
    {1, 1, 1, 1}};

extern void keyAction(unsigned char keyCode); // 按钮响应动作函数,需要在main.c中定义

/*按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用*/
void keyDriver()
{
    unsigned char i, j;
    static unsigned char pdata backup[4][4] = {// 按键值备份,保存前一次的值
                                               {1, 1, 1, 1},
                                               {1, 1, 1, 1},
                                               {1, 1, 1, 1},
                                               {1, 1, 1, 1}};

    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 4; j++)
        {
            if (backup[i][j] != keySta[i][j])
            { // 检测按键动作
                if (backup[i][j] == 1)
                { // 按键按下时执行动作
                    keyAction(keyCodeMap[i][j]);
                }
                backup[i][j] = keySta[i][j];
            }
        }
    }
}
/*按键扫描函数,需在定时器中断中调用,推荐调用间隔1ms*/
void keyScan()
{
    unsigned char i;
    static unsigned char keyOut = 0;     // 矩阵按键扫描输出索引
    static unsigned char pdata keyBuf[4][4] = {// 矩阵按键扫描缓存
                                         {0xFF, 0xFF, 0xFF, 0xFF},
                                         {0xFF, 0xFF, 0xFF, 0xFF},
                                         {0xFF, 0xFF, 0xFF, 0xFF},
                                         {0xFF, 0xFF, 0xFF, 0xFF}};

    keyBuf[keyOut][0] = (keyBuf[keyOut][0] << 1) | keyOut_1;
    keyBuf[keyOut][1] = (keyBuf[keyOut][1] << 1) | keyOut_2;
    keyBuf[keyOut][2] = (keyBuf[keyOut][2] << 1) | keyOut_3;
    keyBuf[keyOut][3] = (keyBuf[keyOut][3] << 1) | keyOut_4;

    for (i = 0; i < 4; i++)
    {
        if ((keyBuf[keyOut][i] & 0x0F) == 0x0F)
        {
            keySta[keyOut][i] = 1;
        }
        else if ((keyBuf[keyOut][i] & 0x0F) == 0x00)
        {
            keySta[keyOut][i] = 0;
        }
    }

    switch (keyOut)
    {
    case 0:
        keyIn_1 = 1;
        keyIn_2 = 0;
        keyOut++;
        break;
    case 1:
        keyIn_2 = 1;
        keyIn_3 = 0;
        keyOut++;
        break;
    case 2:
        keyIn_3 = 1;
        keyIn_4 = 0;
        keyOut++;
        break;
    case 3:
        keyIn_4 = 1;
        keyIn_1 = 0;
        keyOut = 0;
        break;
    default:
        break;
    }
}

使用示例(计算器)

main.c

#include <REG52.H>

unsigned char step = 0; // 操作步数,0——第一步(num1),1——第二步(num2),2——第三步(result)
unsigned char oprt = 0; // 操作符
signed long num1 = 0;   // 第一个数
signed long num2 = 0;   // 第二个数
signed long result = 0; // 结果
unsigned char T0RH = 0;
unsigned char T0RL = 0;

void configTimer0(unsigned int ms);
extern void keyScan();
extern void keyDriver();
extern void initLCD1602();
extern void lcdShowStr(unsigned char x, unsigned char y,
                       unsigned char *str);
extern void lcdAreaClear(unsigned char x, unsigned char y, unsigned char len);
extern void lcdFullClear();

void main()
{
    EA = 1;
    configTimer0(1);
    initLCD1602();
    lcdShowStr(15, 1, "0"); // 在第二行最左边输出一个0

    while (1)
    {
        keyDriver();
    }
}
/*将dat转换为字符串*/
unsigned char longToString(unsigned char *str, signed long dat)
{
    signed char i = 0;
    unsigned char len = 0; // 转换后的字符串长度
    unsigned char buf[12];

    if (dat < 0) // 如果dat是负数,要将dat转换为正数
    {
        dat = -dat;
        *str++ = '-'; // 在str最左侧加上一个负号
        len++;
    }
    /*两次转换是为了不让字符串颠倒*/
    do
    {
        buf[i++] = dat % 10 + '0';
        dat /= 10;
    } while (dat > 0);
    len += i;
    while (i--)
    {
        *str++ = buf[i];
    }
    *str = '\0';

    return len;
}
/*显示运算符*/
void showOprt(unsigned char y, unsigned char type)
{
    switch (type)
    {
    case 0:
        lcdShowStr(0, y, "+");
        break;
    case 1:
        lcdShowStr(0, y, "-");
        break;
    case 2:
        lcdShowStr(0, y, "*");
        break;
    case 3:
        lcdShowStr(0, y, "/");
        break;
    default:
        break;
    }
}
/*计算器复位,清零变量,清除屏幕显示*/
void reset()
{
    num1 = 0;
    num2 = 0;
    step = 0;
    lcdFullClear();
}
/*数字键动作函数,n为按键输入的数值*/
void numKeyAction(unsigned char n)
{
    unsigned char len;
    unsigned char str[12];

    if (step > 1) // 如果计算完成,要重新开始进行新的运算
    {
        reset();
    }
    if (step == 0) // 输入第一个数字
    {
        num1 = num1 * 10 + n;
        len = longToString(str, num1);
        lcdShowStr(16 - len, 1, str);
    }
    else // 输入第二个数字
    {
        num2 = num2 * 10 + n;
        len = longToString(str, num2);
        lcdShowStr(16 - len, 1, str);
    }
}
/*运算符按键动作函数*/
void oprtKeyAction(unsigned char type)
{
    unsigned char len;
    unsigned char str[12];

    if (step == 0) // 第二个数字没有输入的时候响应,不支持连续操作
    {
        len = longToString(str, num1); // 第一操作数转换为字符串
        lcdAreaClear(0, 0, 16 - len);  // 清除第一行左边的字符位
        lcdShowStr(16 - len, 0, str);  // 字符串靠右显示在第一行
        showOprt(1, type);
        lcdAreaClear(1, 1, 14);
        lcdShowStr(15, 1, "0");
        oprt = type;
        step = 1;
    }
}

void getResult()
{
    unsigned char len;
    unsigned char str[12];

    if (step == 1)
    {
        step = 2;
        switch (oprt)
        {
        case 0:
            result = num1 + num2;
            break;
        case 1:
            result = num1 - num2;
            break;
        case 2:
            result = num1 * num2;
            break;
        case 3:
            result = num1 / num2;
            break;
        default:
            break;
        }
        len = longToString(str, num2);
        showOprt(0, oprt);
        lcdAreaClear(1, 0, 16 - 1 - len);
        lcdShowStr(16 - len, 0, str);
        len = longToString(str, result);
        lcdShowStr(0, 1, "=");
        lcdAreaClear(1, 1, 16 - 1 - len);
        lcdShowStr(16 - len, 1, str);
    }
}

void keyAction(unsigned char keyCode)
{
    if (keyCode >= 0x00 && keyCode <= 0x09)
    {
        numKeyAction(keyCode);
    }
    else if (keyCode == 0x0A)
    {
        oprtKeyAction(0);
    }
    else if (keyCode == 0x0B)
    {
        oprtKeyAction(1);
    }
    else if (keyCode == 0x0C)
    {
        oprtKeyAction(2);
    }
    else if (keyCode == 0x0D)
    {
        oprtKeyAction(3);
    }
    else if (keyCode == 0x0E)
    {
        getResult();
    }
    else if (keyCode == 0x0F)
    {
        reset();
        lcdShowStr(15, 1, "0");
    }
}

void configTimer0(unsigned int ms)
{
    unsigned long temp;

    temp = 11059200 / 12;
    temp = (temp * ms) / 1000;
    temp = 65536 - temp;
    temp = temp + 29; // 等待校准
    T0RH = (unsigned char)(temp >> 8);
    T0RL = (unsigned char)temp;
    TMOD &= 0xF0;
    TMOD |= 0x01;
    TH0 = T0RH;
    TL0 = T0RL;
    ET0 = 1;
    TR0 = 1;
}

void interruptTimer0() interrupt 1
{
    TH0 = T0RH;
    TL0 = T0RL;
    keyScan();
}

keyboard.c

#include <REG52.H>

sbit keyIn_1 = P1 ^ 7;
sbit keyIn_2 = P1 ^ 6;
sbit keyIn_3 = P1 ^ 5;
sbit keyIn_4 = P1 ^ 4;
sbit keyOut_1 = P1 ^ 3;
sbit keyOut_2 = P1 ^ 2;
sbit keyOut_3 = P1 ^ 1;
sbit keyOut_4 = P1 ^ 0;

unsigned char code keyCodeMap[4][4] = {
    {0x01, 0x02, 0x03, 0x0A},
    {0x04, 0x05, 0x06, 0x0B},
    {0x07, 0x08, 0x09, 0x0C},
    {0x0E, 0x00, 0x0F, 0x0D}};

unsigned char pdata keySta[4][4] = {
    {1, 1, 1, 1},
    {1, 1, 1, 1},
    {1, 1, 1, 1},
    {1, 1, 1, 1}};

extern void keyAction(unsigned char keyCode); // 按钮响应动作函数,需要在main.c中定义

/*按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用*/
void keyDriver()
{
    unsigned char i, j;
    static unsigned char pdata backup[4][4] = {// 按键值备份,保存前一次的值
                                               {1, 1, 1, 1},
                                               {1, 1, 1, 1},
                                               {1, 1, 1, 1},
                                               {1, 1, 1, 1}};

    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 4; j++)
        {
            if (backup[i][j] != keySta[i][j])
            { // 检测按键动作
                if (backup[i][j] == 1)
                { // 按键按下时执行动作
                    keyAction(keyCodeMap[i][j]);
                }
                backup[i][j] = keySta[i][j];
            }
        }
    }
}
/*按键扫描函数,需在定时器中断中调用,推荐调用间隔1ms*/
void keyScan()
{
    unsigned char i;
    static unsigned char keyOut = 0;     // 矩阵按键扫描输出索引
    static unsigned char pdata keyBuf[4][4] = {// 矩阵按键扫描缓存
                                         {0xFF, 0xFF, 0xFF, 0xFF},
                                         {0xFF, 0xFF, 0xFF, 0xFF},
                                         {0xFF, 0xFF, 0xFF, 0xFF},
                                         {0xFF, 0xFF, 0xFF, 0xFF}};

    keyBuf[keyOut][0] = (keyBuf[keyOut][0] << 1) | keyOut_1;
    keyBuf[keyOut][1] = (keyBuf[keyOut][1] << 1) | keyOut_2;
    keyBuf[keyOut][2] = (keyBuf[keyOut][2] << 1) | keyOut_3;
    keyBuf[keyOut][3] = (keyBuf[keyOut][3] << 1) | keyOut_4;

    for (i = 0; i < 4; i++)
    {
        if ((keyBuf[keyOut][i] & 0x0F) == 0x0F)
        {
            keySta[keyOut][i] = 1;
        }
        else if ((keyBuf[keyOut][i] & 0x0F) == 0x00)
        {
            keySta[keyOut][i] = 0;
        }
    }

    switch (keyOut)
    {
    case 0:
        keyIn_1 = 1;
        keyIn_2 = 0;
        keyOut++;
        break;
    case 1:
        keyIn_2 = 1;
        keyIn_3 = 0;
        keyOut++;
        break;
    case 2:
        keyIn_3 = 1;
        keyIn_4 = 0;
        keyOut++;
        break;
    case 3:
        keyIn_4 = 1;
        keyIn_1 = 0;
        keyOut = 0;
        break;
    default:
        break;
    }
}

LCD1602.c

// 基于普中51开发板——LCD1601驱动
#include <REG52.H>

#define LCD1602_DB P0

sbit LCD1602_RS = P2 ^ 6;
sbit LCD1602_RW = P2 ^ 5;
sbit LCD1602_EN = P2 ^ 7;

/*等待液晶准备好*/
void lcdWaitReady()
{
    unsigned char sta;

    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do
    {
        LCD1602_EN = 1;
        sta = LCD1602_DB; // 读取状态字
        LCD1602_EN = 0;
    } while (sta & 0x80); // bit_7为1时表示液晶正忙,重复检测直到其等于1为止
}
/*向LCD1602液晶写入一字节命令,cmd为待写入命令值*/
void lcdWriteCmd(unsigned char cmd)
{
    lcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_EN = 1;
    LCD1602_EN = 0;
}
/*向LCD1602液晶写入一字节命令,dat为待写入命令*/
void lcdWriteDta(unsigned char dat)
{
    lcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_EN = 1;
    LCD1602_EN = 0;
}
/*设置显示RAM起始地址,亦即光标位置,(x,y)为对应屏幕上的字符坐标*/
void lcdSetCursor(unsigned char x, unsigned char y)
{
    unsigned char addr;

    if (y == 0)
    {                    // 由输入的屏幕坐标计算显示RAM的地址
        addr = 0x00 + x; // 第一行字符地址从0x00起始
    }
    else
    {
        addr = 0x40 + x; // 第二行字符地址从0x40起始
    }
    lcdWriteCmd(addr | 0x80); // 设置RAM地址
}
/*在液晶上显示字符串,(x,y)为对应屏幕上的起始坐标,str为字符串指针*/
void lcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
{
    lcdSetCursor(x, y); // 设置起始地址
    while (*str != '\0')
    {                        // 连续写入字符串数据,直到检测到结束符
        lcdWriteDta(*str++); // 先取str指向的数据,然后str自加1
    }
}
/*区域清除,清除从(x,y)坐标起始的len个字符*/
void lcdAreaClear(unsigned char x, unsigned char y, unsigned char len)
{
    lcdSetCursor(x, y);
    while (len--)
    {
        lcdWriteDta(' ');
    }
}
/*清屏指令*/
void lcdFullClear()
{
    lcdWriteCmd(0x01);
}
/*初始化1602液晶*/
void initLCD1602()
{
    lcdWriteCmd(0x38); // 16*2显示,5*7点阵,8位数据接口
    lcdWriteCmd(0x0C); // 显示器开,光标关闭
    lcdWriteCmd(0x06); // 文字不动,地址自动+1
    lcdWriteCmd(0x01); // 清屏
}

UART.c

#include <REG52.H>

bit flagFrame = 0;              // 帧接收完成标志,即接收到一帧新数据
bit flagTxd = 0;                // 单字节发送完成标志,用来替代TXD中断标志位
unsigned char cntRxd = 0;       // 接收字节计数器
unsigned char pdata bufRxd[64]; // 接收字节缓冲区

extern void uartAction(unsigned char *buf, unsigned char len);

/*串口配置函数*/
void configUART(unsigned int baud)
{
    SCON = 0x50;
    TMOD &= 0x0F;
    TMOD |= 0x20;
    TH1 = 256 - 11059200 / 12 / 2 / 16 / baud;
    TL1 = TH1;
    ES = 1;
    TR1 = 1;
}
/*串口数据写入,即串口发送函数,buf为待发送数据的指针,len为指定的发送长度*/
void uartWrite(unsigned char *buf, unsigned char len)
{
    while (len--)
    {                  // 循环发送所有字节
        flagTxd = 0;   // 清零发送标志
        SBUF = *buf++; // 发送一个字节数据
        while (!flagTxd)
            ; // 等待该字节发送完毕
    }
}
/*串口数据读取函数,buf为接收指针,len为指定的读取长度,返回值为实际读取到的长度*/
unsigned char uartRead(unsigned char *buf, unsigned char len)
{
    unsigned char i;

    if (len > cntRxd)
    {                 // 指定读取长度大于实际接收到的数据长度时
        len = cntRxd; // 读取长度设置为实际接受到的数据长度
    }
    for (i = 0; i < len; i++)
    { // 复制接收到的数据到接收指针上
        *buf++ = bufRxd[i];
    }
    cntRxd = 0; // 接收计数器请零

    return len;
}
/*串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms为定时间隔*/
void uartMonitor(unsigned char ms)
{
    static unsigned char cntBkp = 0;
    static unsigned char tm = 0;

    if (cntRxd > 0)
    { // 接收计数器大于0,监控总线空闲时间
        if (cntBkp != cntRxd)
        { // 接收计数器改变,即刚接收到数据时,清0空闲计时器
            cntBkp = cntRxd;
            tm = 0;
        }
        else
        { // 接收计数器未改变,即总线空闲时,累积空闲时间
            if (tm < 30)
            { // 空闲时间小于30ms(经验值)
                tm += ms;
                if (tm >= 30)
                {                  // 空闲时间达到30ms时,即判定为一帧接收完毕
                    flagFrame = 1; // 设置帧接收完成标志
                }
            }
        }
    }
    else
    {
        cntBkp = 0;
        tm = 0;
    }
}
/*串口驱动函数,检测数据帧的接收,调度功能函数,需在主循环中调用*/
void uartDriver()
{
    unsigned char len;
    unsigned char pdata buf[40];//按需调整

    if (flagFrame) // 有命令到达时,读取处理该命令
    {
        flagFrame = 0;
        len = uartRead(buf, sizeof(buf)); // 将接收到的命令读取到缓冲区中
        uartAction(buf, len);             // 传递数据帧,调用动作执行函数
    }
}
/*串口中断服务函数*/
void interruptUART() interrupt 4
{
    if (RI) // 接收到新字节
    {
        RI = 0;                      // 清0接收中断标志位
        if (cntRxd < sizeof(bufRxd)) // 接收缓冲区尚未用完
        {
            bufRxd[cntRxd++] = SBUF; // 保存接收字节,并递增计数器
        }
    }
    if (TI) // 字节发送完毕
    {
        TI = 0;      // 清零发送中断标志位
        flagTxd = 1; // 设置字节发送完成标志
    }
}
最后修改:2024 年 08 月 07 日
如果觉得我的文章对你有用,请随意赞赏