欢迎光临散文网 会员登陆 & 注册

第13章-1602液晶与串口的应用实例

2023-09-13 00:21 作者:feifeiluan2  | 我要投稿

代码分模块组织,多个文件,反而不好往出粘贴了

keil那个写代码的,真垃圾,破玩意,一点也不智能


//课后习题,问题像右移动

#include <reg52.h>

#define LCD1602_DB   P0
sbit LCD1602_RS =  P1^0;
sbit LCD1602_RW =  P1^1;
sbit LCD1602_E  =  P1^5;

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

    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do {
        LCD1602_E = 1;
        sta = LCD1602_DB; //读取状态字
        LCD1602_E = 0;
    } while (sta & 0x80); //bit7等于1表示液晶正忙,重复检测直到其等于0为止
}
/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */
void LcdWriteCmd(unsigned char cmd)
{
    LcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}

void LcdSetCursorHL(unsigned char hang, unsigned char lie)
{
    unsigned char addr;

    if (hang == 0)  //由输入的屏幕坐标计算显示RAM的地址
        addr = 0x00 + lie;  //第一行字符地址从0x00起始
    else
        addr = 0x40 + lie;  //第二行字符地址从0x40起始
    LcdWriteCmd(addr | 0x80);  //设置RAM地址
}

void LcdShowStrHL(unsigned char hang, unsigned char lie, unsigned char *str)
{
    LcdSetCursorHL(hang, lie);   //设置起始地址
    while (*str != '\0')  //连续写入字符串数据,直到检测到结束符
    {
        LcdWriteDat(*str++);
    }
}

/* 初始化1602液晶 */
void InitLcd1602()
{
    LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
    LcdWriteCmd(0x0C);  //显示器开,光标关闭
    LcdWriteCmd(0x06);  //文字不动,地址自动+1
    LcdWriteCmd(0x01);  //清屏
}

unsigned char TH0RL,TL0RL;
bit flag500ms=0;

void main()
{
    unsigned char  i,cnt,strlen;

    char str1[]="www.bilibili.com";;
    char str2[]="www.qdkingst.com";

    EA = 1;           //开总中断
    ConfigTimer0(1);  //配置T0定时1ms
    InitLcd1602();    //初始化液晶

    //显示字符串
    LcdShowStrHL(0,0,str1);
    LcdShowStrHL(1,0,str2);

    //16个空白,字符串,剩下的空白
    strlen=sizeof(str1);
    LcdWriteCmd(0x02);
    for(i=0;i<strlen;i++)
    {
        LcdWriteCmd(0x18);//提前移动
    }
    flag500ms=0;
    cnt=0;
    while (1)
    {
        if(flag500ms)
        {
            flag500ms=0;
            LcdWriteCmd(0x1C);//像右移动
            cnt++;
            if(cnt==strlen*2)
            {
                cnt=0;
                LcdWriteCmd(0x02);
                for(i=0;i<strlen;i++)
                {
                    LcdWriteCmd(0x18);//提前移动
                }
            }
        }
    }
}

/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0(unsigned int ms)
{
    unsigned int tmp= 65536 - 11059200/12*ms/1000;

    TMOD =(TMOD & 0xF0)|0x01;
    TH0=TH0RL = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
    TL0=TL0RL = (unsigned char)tmp;
    
    ET0=TR0 = 1;        //启动T0
}
/* T0中断服务函数,执行按键扫描 */
void Timer0_ISR() interrupt 1
{
    static unsigned int cnt=0;
    
    TH0 = TH0RL;  //重新加载重载值
    TL0 = TL0RL;
    
    if(++cnt>=500)
    {
        flag500ms=1;
        cnt=0;
    }
}


//课后第5题,老师的看不太懂,用自己的思路实现
//直接在老师的代码上修改,懒得写了,组织的乱七八糟

#include <stdio.h>
#include <string.h>

//Lcd1602部分
#include <reg52.h>

#define LCD1602_DB   P0
sbit LCD1602_RS =  P1^0;
sbit LCD1602_RW =  P1^1;
sbit LCD1602_E  =  P1^5;

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

    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do
    {
        LCD1602_E = 1;
        sta = LCD1602_DB; //读取状态字
        LCD1602_E = 0;
    }
    while (sta & 0x80);   //bit7等于1表示液晶正忙,重复检测直到其等于0为止
}
/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */
void LcdWriteCmd(unsigned char cmd)
{
    LcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}

void LcdSetCursorHL(unsigned char hang, unsigned char lie)
{
    unsigned char addr;

    if (hang == 0)  //由输入的屏幕坐标计算显示RAM的地址
        addr = 0x00 + lie;  //第一行字符地址从0x00起始
    else
        addr = 0x40 + lie;  //第二行字符地址从0x40起始
    LcdWriteCmd(addr | 0x80);  //设置RAM地址
}

void LcdShowStrHL(unsigned char hang, unsigned char lie, unsigned char *str)
{
    LcdSetCursorHL(hang, lie);   //设置起始地址
    while (*str != '\0')  //连续写入字符串数据,直到检测到结束符
    {
        LcdWriteDat(*str++);
    }
}

/* 初始化1602液晶 */
void InitLcd1602()
{
    LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
    LcdWriteCmd(0x0C);  //显示器开,光标关闭
    LcdWriteCmd(0x06);  //文字不动,地址自动+1
    LcdWriteCmd(0x01);  //清屏
}


//Uart部分
unsigned char UartRecBuff[32];//接收缓冲区
unsigned char UartRecCnt=0;//接收的字节数
bit flagUartRecOK=0;//是否一帧结束---结束就可以读取数据了

unsigned char UartMsCnt=0;//判断一帧结束的计数器
bit flagUartMsCntEn=0;//是否开启判断一帧结束的计数器

bit flagSentBusy=0;//是否uart正在发送

sbit BUZZ = P1^6;  //蜂鸣器控制引脚
bit flagBuzzOn = 0;   //蜂鸣器启动标志


/* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */
unsigned char UartRead(unsigned char *buf, unsigned char len)
{
    unsigned char i;
    unsigned char retCnt= (UartRecCnt<=len)?UartRecCnt:len;//取小值

    for(i=0; i<retCnt; i++)
    {
        buf[i]=UartRecBuff[i];
        UartRecCnt--;
    }

    if(UartRecCnt==0)
    {
        flagUartRecOK=0;//数据取完了,
    }

    return retCnt;
}

// 串口数据写入,阻塞式发送数据
void UartSent(unsigned char *buf, unsigned char len)
{
    while (len--)  //循环发送所有字节
    {
        flagSentBusy = 1;      //清零发送标志
        SBUF = *buf++;    //发送一个字节数据
        while (flagSentBusy); //等待该字节发送完成
    }
}

/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{
    SCON  = 0x50;  //配置串口为模式1
    ES=1;

    TMOD =(TMOD&0x0F)| 0x20;  //配置T1为模式2
    TH1 =TL1= 256 - (11059200/12/32)/baud;  //计算T1重载值
    ET1 = 0;       //禁止T1中断
    TR1 = 1;       //启动T1
}

void UartAction(unsigned char * buf,unsigned char len)
{
    unsigned char i;
    unsigned char * cmd[]= {"buzz on","buzz off","showstr "};

    for(i=0; i<3; i++)
    {
        unsigned char cmdLen=strlen(cmd[i]);

        if(memcmp(buf,cmd[i],cmdLen)==0)
        {
            if(i==0)
            {
                flagBuzzOn=1;
            }
            else if(i==1)
            {
                flagBuzzOn=0;
            }
            else if(i==2)
            {
                unsigned char pdata tmp[32]= {0};

                memcpy(tmp,buf+cmdLen,len-cmdLen);

                LcdWriteCmd(0x01);
                LcdShowStrHL(0,0,tmp);
            }

            UartSent(buf,len);
            return;
        }
    }
    UartSent("Bad Common: ",strlen("Bad Common: "));
    UartSent(buf,len);
}

/* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
void UartDriver()
{
    unsigned char pdata buf[32];

    if (flagUartRecOK) //有命令到达时,读取处理该命令
    {
        unsigned char len = UartRead(buf, sizeof(buf));  //将接收到的命令读取到缓冲区中
        UartAction(buf, len);  //传递数据帧,调用动作执行函数
    }
}

/* 串口中断服务函数 */
void UART_ISR() interrupt 4
{
    if (RI)  //接收到新字节
    {
        RI = 0;  //清零接收中断标志位
        if (UartRecCnt < sizeof(UartRecBuff)) //接收缓冲区尚未用完时,
        {
            //保存接收字节,从0开始计数
            UartRecBuff[UartRecCnt++] = SBUF;
            UartMsCnt=0;//计数清零
            flagUartMsCntEn=1;//开启计数
        }
        else //数据太多,接收满了
        {
            flagUartMsCntEn=0;//不用计数了
            flagUartRecOK=1;//直接结束接收
        }
    }
    if (TI)  //字节发送完毕
    {
        TI = 0;   //清零发送中断标志位
        flagSentBusy = 0;  //设置字节发送完成标志
    }
}

void int_1ms_uart_task(void)
{
    if(flagUartMsCntEn)//是否需要计数
    {
        if(++UartMsCnt>=50)//50ms
        {
            flagUartMsCntEn=0;//不用计数了
            flagUartRecOK=1;//直接结束接收
        }
    }
}

unsigned char TH0RL,TL0RL;

/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0(unsigned int ms)
{
    unsigned int tmp= 65536 - 11059200/12*ms/1000;

    TMOD =(TMOD & 0xF0)|0x01;
    TH0=TH0RL = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
    TL0=TL0RL = (unsigned char)tmp;

    ET0=TR0 = 1;        //启动T0
}

/* T0中断服务函数,执行按键扫描 */
void Timer0_ISR() interrupt 1
{
    TH0 = TH0RL;  //重新加载重载值
    TL0 = TL0RL;

    if(flagBuzzOn)
        BUZZ=!BUZZ;
    else
        BUZZ=1;

    int_1ms_uart_task();
}

void main ()
{
    EA = 1;            //开总中断
    ConfigTimer0(1);   //配置T0定时1ms
    ConfigUART(9600);  //配置波特率为9600
    InitLcd1602();     //初始化液晶

    while (1)
    {
        UartDriver();  //调用串口驱动
    }
}



第13章-1602液晶与串口的应用实例的评论 (共 条)

分享到微博请遵守国家法律