You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

双Atmega328p架构GSM-P10电子公告板串口消息截断问题求助

双Atmega328P架构GSM电子公告板消息接收截断问题

系统架构说明

采用两块Atmega328P单片机拆分功能,规避DMD库与SoftwareSerial库的冲突:

  • 单片机1:对接SIM800L模块,接收短信后通过串口转发消息
  • 单片机2:对接P10显示模块,接收串口消息并滚动显示

当前问题:单片机2接收的消息存在截断,无法完整显示。

单片机1(短信接收与转发)代码

#include <SIM800L.h>
SIM800L sim800l(2, 3); //Rx, Tx
int LED_PIN = 8;

//Enter the phone number of the person whom you want to send sms
String reply = "Hey! I have got your message";

void handleSMS(String number, String message) {
  int start_index = message.indexOf('*'); // message starts with '*'
  int end_index = message.indexOf('#'); // message ends with '*'
  //message.trim();
  // if message starts with * and ends with #
  if(start_index == 0 && end_index == (message.length() - 1)) {
    Serial.println(message);
    blinkLed();
    sim800l.sendSMS(number, reply);
  } 
}

void setup() {
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);
  sim800l.begin(9600);
  sim800l.setSMSCallback(handleSMS);
}

void loop() {
  sim800l.listen();
}

void blinkLed(){
   for(int i = 0; i < 3; i++){
      digitalWrite(LED_PIN, HIGH);
      delay(1000);
      digitalWrite(LED_PIN, LOW);
      delay(1000);
 }
}

单片机2(消息接收与P10显示)代码

#include <SPI.h>
#include  "buzzer.h"
#include <DMD.h>
#include "memory.h"

#include <TimerOne.h>

#include "SystemFont5x7.h"

#include "Arial_black_16.h"


#define ROW 3

#define COLUMN 1

#define FONT Arial_Black_16
char message [250] = "Welcome to electronic projects workshop 1234";
char r_msg[250] = "";
bool flag = false;

DMD led_module(ROW, COLUMN);


void scan_module()

{

  led_module.scanDisplayBySPI();

}


void setup()

{
  EEPROM.begin();
  Serial.begin(9600);
  buzzerSetup();
  beeps(3);

  int m_length = EEPROM.read(5);
 
    //    strcpy(message, "");
  String stored_string = read_string(5); 
     
  char stored_char[stored_string.length() + 1];
  stored_string.toCharArray(stored_char, stored_string.length() + 1); // convert message from string to array of char
  strcpy(message, stored_char); // update p10 with stored message

  
  Timer1.initialize(2000);

  Timer1.attachInterrupt(scan_module);

 led_module.clearScreen( true );
writeString(5, "Hello people");
}

void loop()

{
  Serial.println(read_string(5)); 
    receiveMessage();
    
    led_module.selectFont(FONT);

    led_module.drawMarquee(message, strlen(message), (32 * ROW), 0);

    long start = millis();

    long timming = start;

    boolean flag = false;

    while (!flag)

    {

      if ((timming + 20) < millis()) 

      {

        flag = led_module.stepMarquee(-1, 0);

        timming = millis();
      }
    }

  }

void receiveMessage()
{
  /*
    Listens to incoming message through serial interface. 
    It extracts the message if it starts with '*' and ends with '#'
  */
  while(Serial.available())
  {
    String s_msg = Serial.readString();
    // s_msg.trim();
    int start_index = s_msg.indexOf('*') + 1;
    int end_index = s_msg.indexOf('#');
      
    // whether message contains * and # and also # comes after *
    if(start_index > 0 ){
        beeps(1);
        String substr = s_msg.substring(start_index, end_index - 1);
        int m_len = substr.length() + 1;
        char m_msg [m_len];
        substr.toCharArray(m_msg, m_len);
        
        strcpy(message, m_msg);
        // write to eeprom
        writeString(5, substr);
      }
   }
}

问题排查与解决方案

核心问题分析

  1. 串口接收逻辑缺陷:单片机2的receiveMessage()中使用Serial.readString(),该函数默认超时后返回,若消息较长或串口传输有延迟,会导致单次读取不完整。
  2. 消息边界处理错误:substring(start_index, end_index - 1)多减1,会丢失#前的最后一个字符。
  3. 主循环阻塞:单片机2的loop()中,滚动显示的while循环会持续阻塞直到完成,期间无法及时响应串口接收,导致后续字节丢失。

修复步骤

1. 修正串口接收逻辑,按边界完整读取

修改receiveMessage()为逐字节读取,直到收到结束符#:

void receiveMessage()
{
  static String buffer = "";
  while(Serial.available())
  {
    char c = Serial.read();
    buffer += c;
    // 检测到结束符#,处理完整消息
    if(c == '#'){
      int start_index = buffer.indexOf('*');
      int end_index = buffer.indexOf('#');
      // 验证消息格式:*开头,#结尾且顺序正确
      if(start_index == 0 && end_index == buffer.length() - 1){
        beeps(1);
        String substr = buffer.substring(1, end_index); // 取*和#之间的内容
        int m_len = substr.length() + 1;
        char m_msg [m_len];
        substr.toCharArray(m_msg, m_len);
        
        strcpy(message, m_msg);
        writeString(5, substr);
      }
      // 清空缓冲区,准备接收下一条消息
      buffer = "";
    }
  }
}

2. 优化主循环,避免阻塞

将滚动显示改为非阻塞方式,确保串口接收及时响应:

// 全局变量记录滚动状态
bool isScrolling = false;
long marqueeTimer = 0;

void loop()
{
  Serial.println(read_string(5)); 
  receiveMessage();
  
  if(!isScrolling){
    led_module.selectFont(FONT);
    led_module.drawMarquee(message, strlen(message), (32 * ROW), 0);
    isScrolling = true;
    marqueeTimer = millis();
  }
  
  if(isScrolling){
    if(millis() - marqueeTimer >= 20){
      bool finished = led_module.stepMarquee(-1, 0);
      marqueeTimer = millis();
      if(finished){
        isScrolling = false;
      }
    }
  }
}

3. 调整单片机1的发送逻辑(可选)

发送消息时确保串口传输完整,避免额外换行干扰:

// 修改handleSMS中的发送逻辑
if(start_index == 0 && end_index == (message.length() - 1)) {
  Serial.print(message); // 用print代替println,避免额外换行
  // 等待串口发送完成
  while(Serial.availableForWrite() < message.length());
  blinkLed();
  sim800l.sendSMS(number, reply);
}

内容的提问来源于stack exchange,提问作者Bello Shehu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 03:39:52