司败的man 2024-05-22 00:52 采纳率: 66.7%
浏览 34

51单片机串口通信lcd显示

我利用普中 51 开发版和 lcd 1602 想完成通过虚拟助手发送数据 lcd 屏幕显示的功能,我的代码改过几次,有时显示不了,有时显示的最后出现四条横杠一样的东西,有的时候只能显示传输的前两个数字,有没有哥们能指点以下问题所在
以下是我的代码

#include "reg52.h"
#include "lcd1602.h"

#define DATA_LCD_SIZE 32 // 增加数组大小以存储更多数据
u8 data_lcd[DATA_LCD_SIZE] = {0}; // 初始化数组
volatile u8 data_received = 0; // 接收到的数据
volatile u8 data_index = 0; // 数组索引
volatile u8 new_data_flag = 0; // 新数据标志

/*******************************************************************************
* 函 数 名       : uart_init
* 函数功能       : 串口通信中断配置函数
* 输    入       : baud:波特率对应的TH、TL装载值
* 输    出        : 无
*******************************************************************************/
void uart_init(u8 baud)
{
    TMOD |= 0X20;  // 设置计数器工作方式2
    SCON = 0X50;   // 设置为工作方式1
    PCON = 0X80;   // 波特率加倍
    TH1 = baud;    // 计数器初始值设置
    TL1 = baud;
    ES = 1;        // 打开接收中断
    EA = 1;        // 打开总中断
    TR1 = 1;       // 打开计数器
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能       : 主函数
* 输    入       : 无
* 输    出        : 无
*******************************************************************************/
void main()
{
    uart_init(0XFA); // 波特率为9600
    lcd1602_init();  // 初始化LCD1602

    while(1)
    {
        if(new_data_flag) // 如果有新数据标志
        {
            lcd1602_clear(); // 清除LCD
            data_lcd[data_index] = '\0'; // 在字符串末尾添加空字符
            lcd1602_show_string(0, 0, data_lcd); // 显示数据
            new_data_flag = 0; // 清除新数据标志
        }
    }
}

void uart() interrupt 4 // 串口通信中断函数
{
    u8 rec_data;

    RI = 0; // 清除接收中断标志位
    rec_data = SBUF; // 读取接收到的数据

    if(data_index < (DATA_LCD_SIZE - 1)) // 如果数组未满
    {
        data_lcd[data_index] = rec_data; // 存储接收到的数据
        data_index++; // 移动到下一个位置
        new_data_flag = 1; // 设置新数据标志
    }
    else
    {
        // 数组已满,这里可以添加处理逻辑,例如滚动显示或清空数组
        data_index = 0; // 重置索引
        new_data_flag = 1; // 设置新数据标志
    }
}#include "reg52.h"
#include "lcd1602.h"

#define DATA_LCD_SIZE 32 // 增加数组大小以存储更多数据
u8 data_lcd[DATA_LCD_SIZE] = {0}; // 初始化数组
volatile u8 data_received = 0; // 接收到的数据
volatile u8 data_index = 0; // 数组索引
volatile u8 new_data_flag = 0; // 新数据标志

/*******************************************************************************
* 函 数 名       : uart_init
* 函数功能       : 串口通信中断配置函数
* 输    入       : baud:波特率对应的TH、TL装载值
* 输    出        : 无
*******************************************************************************/
void uart_init(u8 baud)
{
    TMOD |= 0X20;  // 设置计数器工作方式2
    SCON = 0X50;   // 设置为工作方式1
    PCON = 0X80;   // 波特率加倍
    TH1 = baud;    // 计数器初始值设置
    TL1 = baud;
    ES = 1;        // 打开接收中断
    EA = 1;        // 打开总中断
    TR1 = 1;       // 打开计数器
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能       : 主函数
* 输    入       : 无
* 输    出        : 无
*******************************************************************************/
void main()
{
    uart_init(0XFA); // 波特率为9600
    lcd1602_init();  // 初始化LCD1602

    while(1)
    {
        if(new_data_flag) // 如果有新数据标志
        {
            lcd1602_clear(); // 清除LCD
            data_lcd[data_index] = '\0'; // 在字符串末尾添加空字符
            lcd1602_show_string(0, 0, data_lcd); // 显示数据
            new_data_flag = 0; // 清除新数据标志
        }
    }
}

void uart() interrupt 4 // 串口通信中断函数
{
    u8 rec_data;

    RI = 0; // 清除接收中断标志位
    rec_data = SBUF; // 读取接收到的数据

    if(data_index < (DATA_LCD_SIZE - 1)) // 如果数组未满
    {
        data_lcd[data_index] = rec_data; // 存储接收到的数据
        data_index++; // 移动到下一个位置
        new_data_flag = 1; // 设置新数据标志
    }
    else
    {
        // 数组已满,这里可以添加处理逻辑,例如滚动显示或清空数组
        data_index = 0; // 重置索引
        new_data_flag = 1; // 设置新数据标志
    }
}


显示函数是这样定义的
lcd1602_show_string(u8 x, u8 y,u8 *ptr)
x:第几排
y:0为第一行,1为第二行

  • 写回答

5条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-05-22 00:53
    关注

    引自免费微信小程序:皆我百晓生

    从您提供的代码来看,主要的问题可能出在以下几个方面:

    1. 数据溢出:当接收到的数据超过data_lcd数组长度时,会导致数据溢出,这可能会导致显示异常。您已经设置了数组大小为32个字节,但仍然有可能溢出,尤其是当接收到连续的大段文本时。

    2. 字符串结束标识:在将接收到的数据存入数组后,记得在字符串的末尾添加一个空字符\0,这是C语言字符串终止的标志。目前看起来您的代码只有在主循环中的数据更新时才会在数组末尾添加空字符,而在中断服务程序里没有这样做,这可能导致显示不完整。

    3. 中断处理:当数组已满时,您将其重置为0并设置新数据标志。然而,在中断处理函数中,您应该先检查新数据标志是否已经清除,如果没有清除,则不应该覆盖现有的数据,因为这意味着主循环可能还没有处理完上一条消息。

    基于以上分析,我建议您对代码进行以下修改:

    首先,确保在中断服务程序中也正确地处理字符串结束标识:

    void uart() interrupt 4 // 串口通信中断函数
    {
        u8 rec_data;
        RI = 0; // 清除接收中断标志位
        rec_data = SBUF; // 读取接收到的数据
        
        if(data_index < (DATA_LCD_SIZE - 1))
        {
            data_lcd[data_index++] = rec_data; // 存储接收到的数据
            if(rec_data == '\n' || data_index == DATA_LCD_SIZE - 1)
                data_lcd[data_index] = '\0'; // 添加空字符,用于字符串结束
            new_data_flag = 1; // 设置新数据标志
        }
        else
        {
            // 数组已满,这里可以添加处理逻辑,例如滚动显示或清空数组
            data_index = 0; // 重置索引
            new_data_flag = 1; // 设置新数据标志
        }
    }
    

    然后,在主循环中检查新数据标志,并根据需要处理数据:

    void main()
    {
        ...
        while(1)
        {
            if(new_data_flag)
            {
                lcd1602_clear(); // 清除LCD
                if(data_lcd[0])
                {
                    lcd1602_show_string(0, 0, data_lcd);
                    data_lcd[data_index] = '\0'; // 确保字符串结束
                }
                new_data_flag = 0; // 清除新数据标志
            }
        }
    }
    

    此外,为了防止数据丢失,可以在中断处理函数中检查新数据标志,如果标志已被清除,表示主循环正在处理数据,此时应该跳过当前的中断处理过程:

    void uart() interrupt 4 // 串口通信中断函数
    {
        u8 rec_data;
        RI = 0; // 清除接收中断标志位
        rec_data = SBUF; // 读取接收到的数据
        
        if(new_data_flag)
        {
            if(data_index < (DATA_LCD_SIZE - 1))
            {
                data_lcd[data_index++] = rec_data; // 存储接收到的数据
                if(rec_data == '\n' || data_index == DATA_LCD_SIZE - 1)
                    data_lcd[data_index] = '\0'; // 添加空字符,用于字符串结束
                new_data_flag = 1; // 设置新数据标志
            }
            else
            {
                // 数组已满,这里可以添加处理逻辑,例如滚动显示或清空数组
                data_index = 0; // 重置索引
                new_data_flag = 1; // 设置新数据标志
            }
        }
    }
    

    这些改动应该可以解决您遇到的显示问题。如果您还有其他疑问或需要进一步的帮助,请随时告诉我。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 5月22日