arduino 中snprintf和sprintf函数的使用注意
arduino 中snprintf和sprintf函数的使用注意
阅读:5

arduino 中snprintf和sprintf函数的使用注意

在 Arduino 的标准库中,Serial.println() 函数并不支持像 C 语言中的 printf 函数那样的格式化字符串。因此,不能直接使用 Serial.println("%d", 1) 这种格式来打印。在 Arduino 中,需要以不同的方式来打印变量。

要想使用类似C语言的格式化打印风格可以使用:

char message[20];
int number = 1;
sprintf(message, "The number is: %d", number);
Serial.println(message);

除了sprintf,另一个更安全的选择是使用 snprintf(),它允许指定缓冲区的最大大小,从而避免溢出:

char buffer[50];
int temperature = 23;
float humidity = 50.5;

snprintf(buffer, sizeof(buffer), "Temperature: %d C, Humidity: %.1f%%", temperature, humidity);
Serial.println(buffer);

值得注意的是两种函数的缓冲存储数组大小一定要比,后面打印的字符串大小要大,否则溢出将可能影响程序当中的其余变量,2024年1月7日调试了下午的BUG:

/******************************Sound_follower*********************************
    @Data: 2024.1.7
    @Version: 1
    @Site: HITSZ
******************************************************************************/
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define Do_C 262
#define Re_D 294
#define Mi_E 330
#define Fa_F 349
#define Sol_G 392
#define La_A 440
#define Si_B 494// 对应每个按键的音符频率(Do_C, Re_D, Mi_E, Fa_F, Sol_G, La_A, Si_B)
#define TITLE "TITLE"

int numberOfButtons = 7;
int buttonPins[] = {2, 3, 4, 5, 6, 7, 8};//numberOfButtons个按键对应的引脚号
volatile bool button_pressed_flag = 0;//按键按下标志位1(有):0(无) 
int button_pressed_num_per_cycle = 0;//每个检测周期按键按下的次数
int buzzerPin = 9;//蜂鸣器对于的引脚号
int Sound_Delay = 500;//单位毫秒
unsigned long lastInterruptTime = 0;// 记录程序执行时间的变量
char message[50];//OLED显示存储变量,需要设置的比显示字符大,否则溢出可能会导致程序中其余变量的值被修改

const int notes[] = {Do_C, Re_D, Mi_E, Fa_F, Sol_G, La_A, Si_B};
// String Display_notes[] = {"Do", "Re", "Mi", "Fa", "Sol", "La", "Si"};//*使用string 无法实现数组的结构化打印,虽然串口显示数据正确,但到OLED就是乱码,原因待查
const char* Display_notes[] = {"Do", "Re", "Mi", "Fa", "Sol", "La", "Si"};


Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);// 初始化OLED显示屏对象,设置分辨率为128x64

void setup() {
  pinMode(buzzerPin, OUTPUT);
  for(int i = 0; i < numberOfButtons; i++){
    pinMode(buttonPins[i], INPUT_PULLUP); 
  }

  Serial.begin(9600);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);// 初始化OLED显示屏
  display.clearDisplay();

  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);//必须得设置文本颜色,不能取消注释

  display.setCursor(10, 30);//(列,行)
  snprintf(message, sizeof(message), "Welcome to %s", TITLE);
  display.println(message);
  display.display();// 更新显示内容
}

void loop() {
  unsigned long currentTime = millis();//记录当前时间,实现按键无阻塞循环检测
  button_pressed_num_per_cycle = 0;
  for(int i = 0; i < numberOfButtons; i++){
    if(digitalRead(buttonPins[i]) == LOW){ // 如果按键被按下
      button_pressed_flag = 1;//按键按下标志位置1
      button_pressed_num_per_cycle ++;//统计一个周期内,numberOfButtons个按键按下的个数
      tone(buzzerPin, notes[i]); // 播放音符
      // while(digitalRead(buttonPins[i]) == LOW); //需要按键按多久,蜂鸣器响多久,就取消改行注释
      display.clearDisplay();
      display.setTextSize(1);
      display.setCursor(10, 8);//(列,行)
      display.println(TITLE);// 显示提示信息 Drawing Shapes
      display.setCursor(8, 25);
      snprintf(message, sizeof(message), "Button %d is pressed!", i);
      // sprintf(message, "Button %d is pressed!", i);
      //使用时message大小如果设置为20,此处会造成缓冲区溢出,下面的button_pressed_flag变量会被修改,为了避免溢出,需要将message的空间设置的比显示字符大
      display.println(message);
      display.setCursor(10, 42);
      snprintf(message, sizeof(message), "Buzzer ON: %s", Display_notes[i]);
      display.println(message);
      display.display();// 更新显示内容
    }
  }

  if (button_pressed_num_per_cycle == 0){//一个扫描周期内无按键按下时,按键按下标志位置0
    button_pressed_flag = 0;
  }

  if ((currentTime - lastInterruptTime > Sound_Delay) && (button_pressed_flag == false)) {// 检查自上次中断以来是否已经过了足够的消抖时间  
    lastInterruptTime = currentTime;
    noTone(buzzerPin); // 延时Sound_Delay,停止播放音符
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(10, 8);//(列,行)
    display.println(TITLE);// 显示提示信息 Drawing Shapes
    display.setCursor(10, 25);
    display.println("No button pressed!");
    display.setCursor(10, 42);
    display.println("Buzzer OFF");
    display.display();// 更新显示内容
  }
}



如果char message[50];/中message的大小被修改为20以内包括20,loop循环中button_pressed_flag 的值竟然会被影响,影响源是snprintf(message, sizeof(message), "Button %d is pressed!", i);中显示的字符刚好达到了20位。

调试了一下午,终于在19点解决了这个BUG:



相关文章
在linux上安装运行virtualBox虚拟机的详细步骤
在linux上安装运行virtualBox虚拟机的详细步骤
阅读:3
在 Windows 11 中将登录方式修改为本地账户登录的步骤
在 Windows 11 中将登录方式修改为本地账户登录的步骤
阅读:2
谷歌简直是疯了,芯片设计软件也开源, gdsfactory
GDSFactory是一个使用Python语言编写的开源设计工具软件包,主要用于快速、高效地生成GDSII(Graphic Data System II)格式的集成电路布局和掩模图形。GDSII是一种
阅读:1