17、MSP430微控制器应用功能详解

MSP430微控制器应用功能详解

1. 初始化设置(Setup Function)

初始化函数 setup() 功能简单,主要任务是显示固件版本并初始化I2C总线。以下是具体代码:

// --------------------------------------------------------------------
void setup()
{
  lcd.begin(20, 4);                    //(SF-1) set up the LCD’s number of columns and rows
  lcd.setCursor(0,0);                  //(SF-2a) Display Firmware version
  lcd.print(“MSP430 DemoBoard”);       //(SF-2b) Display Firmware version
  lcd.setCursor(0,1);                  //(SF-2c) Display Firmware version
  lcd.print(“RTC & Thermometer”);      //(SF-2d) Display Firmware version
  lcd.setCursor(0,2);                  //(SF-2e) Display Firmware version
  lcd.print(“Energia v1.14.36”);       //(SF-2f) Display Firmware version
  lcd.setCursor(0,3);                  //(SF-2g) Display Firmware version
  lcd.print(“24.01.2021”);             //(SF-2h) Display Firmware version
  delay(3000);                         //(SF-3) wait 3 seconds
  lcd.clear();                         //(SF-4) clear display
  Wire.begin();                        //(SF-5) Initialize I2C bus
}
// --------------------------------------------------------------------

其执行步骤如下:
1. (SF - 1)定义LCD为20列4行。
2. (SF - 2a至SF - 2h)显示固件版本信息。
3. (SF - 3)等待3秒。
4. (SF - 4)清除LCD显示。
5. (SF - 5)初始化I2C总线。

2. 主循环(Main Loop)

固件的主循环代码仅两行,如下所示:

// --------------------------------------------------------------------
void loop()
{
  i2c_add = 0b01001000;                //(ML-1) Set default I2C address for temperature sensor
  entry_main();                        //(ML-2) Start the main selection function
}
// --------------------------------------------------------------------

具体操作如下:
1. (ML - 1)设置温度传感器的默认I2C地址,采用“Arduino - Syntax”,默认地址假设A2 = A1 = A0 = GND,为1001 000x。若该地址无响应,将检查其他I2C地址。
2. (ML - 2)跳转到“功能选择”函数。

3. 功能选择(Function Selection)

entry_main() 函数是主选择屏幕,允许选择开发板的四种功能:
1. 温度传感器功能
2. RTC功能
3. 湿度传感器功能
4. 主应用程序

默认情况下,无需选择即可启动主应用程序,只有主应用程序终止时才会显示选择屏幕。以下是代码:

// --------------------------------------------------------------------
// ------------ Main Selection Screen / Entry Screen ------------------
// --------------------------------------------------------------------
void entry_main()
{
  main_app();                             //(EM-1) as default selection start main 
application immedaitely
  while(1)                                //(EM-2) enless-loop
  {
    lcd.clear();                          //(EM-3a) Function selection screen
    lcd.setCursor(0,0);                   //(EM-3b) Function selection screen
    lcd.print(“(1) AT30TSE754”);          //(EM-3c) Function selection screen
    lcd.setCursor(0,1);                   //(EM-3d) Function selection screen
    lcd.print(“(2) RTC: DS1307”);         //(EM-3e) Function selection screen
    lcd.setCursor(0,2);                   //(EM-3f) Function selection screen
    lcd.print(“(3) HYT939”);              //(EM-3g) Function selection screen
    lcd.setCursor(0,3);                   //(EM-3h) Function selection screen
    lcd.print(“(9) Main Application”);    //(EM-3i) Function selection screen
    gv_refresh = 0;                       //(EM-4) shall be the selection screen refreshed?
    while(gv_refresh == 0)                //(EM-5) keyboard-read loop
    {
      read_kbd();                         //(EM-6) read keyboard
      switch(active_key)                  //(EM-7) select function based on key pressed
      {
        case 0x01: i2c_temp_1(); break;   //(EM-8) temperature functions
        case 0x02: i2c_datum_1(); break;  //(EM-9) RTC functions
        case 0x03: hyt939(); break;       //(EM-10) Humidity sensor functions
        case 0x09: main_app(); break;     //(EM-11) Main Application
      }
    }
  }
}
// --------------------------------------------------------------------

执行流程如下:
1. (EM - 1)默认直接启动主应用程序。
2. (EM - 2)进入无限循环。
3. (EM - 3*)显示选择屏幕。
4. (EM - 4至EM - 11)读取键盘输入,根据按键触发相应功能,并在需要时清理LCD。

4. 主应用程序(The Main Application)

main_app() 函数实现了开发板的主要功能,收集传感器和RTC的数据并显示在LCD上。以下是代码的第一部分:

// --------------------------------------------------------------------
// --- Main application: RTC + Temperature
// --------------------------------------------------------------------
void main_app()
{
   byte temp_lsb_old = 0xFE;                  //(MA-1)
   byte temp_lsb_new;                         //(MA-2)
   byte lv_c1;                                //(MA-3)

   lcd.clear();                               //(MA-4)
   w_rtc_txt(1);                              //(MA-5)

   gv_format = 1;                             //(MA-6) display 2 decimal places

   while(active_key != 0xFF) read_kbd();      //(MA-7)
   while(active_key != 0x0E)                  //(MA-8)
   {
// --------------------------------------------------------------------

执行步骤如下:
1. (MA - 1至MA - 3)初始化一些辅助变量。
2. (MA - 4)清除LCD显示。
3. (MA - 5)写入RTC和温度测量的静态文本。
4. (MA - 6)设置温度显示为两位小数。
5. (MA - 7)等待所有按键释放。
6. (MA - 8)进入主循环。

主循环中RTC相关功能代码如下:

// --------------------------------------------------------------------
// -------------------------- RTC -------------------------------------
     i2c_rtc_read();                          //(MA-9)
     if (i2c_answer == 0)                     //(MA-10)
     {
       w_date_time(3);                        //(MA-11)
     }
     else                                     //(MA-12)
     {
       lcd.setCursor(6,0);                    //(MA-13a)
       lcd.print(“--           “);            //(MA-13b)
       lcd.setCursor(6,1);                    //(MA-13c)
       lcd.print(“--           “);            //(MA-13d)
       lcd.setCursor(6,3);                    //(MA-13e)
       lcd.print(“--           “);            //(MA-13f)
     }
// --------------------------------------------------------------------

操作流程:
1. (MA - 9)调用 i2c_rtc_read() 函数读取RTC芯片的当前日期和时间。
2. (MA - 10)若得到预期响应,(MA - 11)显示获取的信息。
3. (MA - 12)若没有响应,在LCD相应位置显示“–”。

湿度传感器数据处理代码如下:

// --------------------------------------------------------------------
// ------------------------- HYT939 -----------------------------------
     gv_hyt939 = hyt939_start();            //(MA-14)
     lcd.setCursor(14,2);                   //(MA-15)
     if(gv_hyt939 == 0)                     //(MA-16)
     {
       hyt939_read();                       //(MA-17)
       lcd.setCursor(14,2);                 //(MA-18a)
       lcd.print(“ “);                      //(MA-18b)
       if(h939_rf_result < 10) lcd.print(“ “); //(MA-18c)
       lcd.print(h939_rf_result, 1);        //(MA-18d)
       lcd.print(“%”);                      //(MA-18e)
     }
     else lcd.print(“      “);              //(MA-19)
     w_rtc_txt(1);                          //(MA-20)
// --------------------------------------------------------------------

操作步骤:
1. (MA - 14)触发湿度测量。
2. (MA - 15)设置LCD写入起始位置。
3. (MA - 16)若有响应,(MA - 17)读取结果并(MA - 18x)显示在LCD上。
4. (MA - 19)若无响应,清理相应显示区域。
5. (MA - 20)重写LCD上的静态文本。

温度测量代码如下:

// --------------------------------------------------------------------
// ------------------------- AT30TSE754 -------------------------------
     find_i2c_temp();                       //(MA-21) find attached I2C sensor
     temp_res = 1;                          //(MA-22a)
     t_change_res();                        //(MA-22b) set resolution to 11 bit
     Wire.beginTransmission(i2c_add);       //(MA-23-01)
     Wire.write(0x00);                      //(MA-23-02)
     i2c_answer = Wire.endTransmission(1);  //(MA-23-03)
     if (i2c_answer == 0)                   //(MA-23-04)
     {
       Wire.requestFrom(i2c_add, 2, 1);     //(MA-23-05) I2C address / 2 bytes // stop
       v_temp_msb =  Wire.read();           //(MA-23-06) read MSB of the temperature
       temp_lsb_new =  Wire.read();         //(MA-23-07) read LSB of the temperature
       if(temp_lsb_old == 0xFE)             //(MA-23-08)
       {
          v_temp_lsb = temp_lsb_new;        //(MA-23-09)
          temp_lsb_old = temp_lsb_new;      //(MA-23-10)
          lv_c1 = 0;                        //(MA-23-11)
       }
       if(temp_lsb_new != temp_lsb_old) lv_c1++; //(MA-23-12)
       else lv_c1 = 0;                      //(MA-23-13)
       if(lv_c1 == 3)                       //(MA-23-14)
       {
          v_temp_lsb = temp_lsb_new;        //(MA-23-15)
          temp_lsb_old = temp_lsb_new;      //(MA-23-16)
          lv_c1 = 0;                        //(MA-23-17)
       }
       w_temp_ub(6,2,1);                    //(MA-23-18)
     }
     else                                   //(MA-24)
     {
        if(gv_hyt939 == 0)                  //(MA-25)
        {
          lcd.setCursor(6,2);               //(MA-26a)
          if(h939_temp_result>=0)           //(MA-24b)
          {
            lcd.print(“+”);                 //(MA-24c)
            if(h939_temp_result < 10) lcd.print(“0”); //(MA-24d)
          }
          lcd.print(h939_temp_result,2);    //(MA-24e)
          lcd.print(char(223));             //(MA-24f)
          lcd.print(“C”);                   //(MA-24g)
        }
        else                                //(MA-25)
        {
          v_temp_lsb = 0xFF;                //(MA-26a)
          w_temp_ub(6,2,1);                 //(MA-26b)
        }
     }
// --------------------------------------------------------------------

操作流程:
1. (MA - 21)查找连接的温度传感器,其I2C地址存储在 i2c_add 中。
2. (MA - 22x)设置测量分辨率为11位。
3. (MA - 23 - 01至MA - 23 - 03)尝试与温度传感器通信。
4. (MA - 23 - 04)若通信成功,(MA - 23 - 05至MA - 23 - 18)读取并显示温度,部分步骤确保显示信息的稳定性。
5. (MA - 24)若通信失败,根据湿度传感器情况显示温度信息。

最后,主循环结束时会再次检查键盘并重新开始:

// --------------------------------------------------------------------
     read_kbd();
     delay(100);
   }
   gv_refresh = 1;
}
// --------------------------------------------------------------------
5. RTC相关功能
5.1 RTC LCD - 仅相关函数

w_rtc_txt(byte x1) 函数用于在选择RTC纯功能或主应用程序运行时写入静态文本。

// --------------------------------------------------------------------
// --------------------------------------------------------------------
void w_rtc_txt(byte x1)
{
  lcd.setCursor(0,0);
  lcd.print(“Date: “);
  lcd.setCursor(0,1);
  lcd.print(“Day : “);
  lcd.setCursor(0,3);
  lcd.print(“Time:”);
  if(x1 == 0)
  {
    lcd.setCursor(17,3);
    lcd.print(“(D)”);
  }
  if(x1 == 1)
  {
    lcd.setCursor(0,2);
    if(gv_hyt939 == 0) lcd.print(“T/H :”);
    else lcd.print(“Temp:”);
  }
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------

x1 为0,假设选择了RTC纯功能,显示“(D)”,表示按“D”可设置日期和时间;若 x1 为1,假设主应用程序运行,根据是否有湿度传感器显示“T/H :”或“Temp:”。

5.2 RTC主函数

i2c_datum_1() 是RTC纯功能的主函数,代码如下:

// --------------------------------------------------------------------
// --------------------------------------------------------------------
// ---- I2C RTC
// --------------------------------------------------------------------
// --------------------------------------------------------------------
void i2c_datum_1()                               //(RTC-1)
{  
   lcd.clear();                                  //(RTC-2)
   w_rtc_txt(0);                                 //(RTC-3)  
   while(active_key != 0xFF) read_kbd();         //(RTC-4)
   while(active_key != 0x0E)                     //(RTC-5)
   {
      w_rtc_txt(0);                              //(RTC-6)
      i2c_rtc_read();                            //(RTC-7)
      if (i2c_answer == 0)                       //(RTC-8)
      {  
        w_date_time(3);                          //(RTC-9)
      }
      else                                       //(RTC-10)
      {
        lcd.setCursor(0,0);                      //(RTC-11a)
        lcd.print(“No answer           “);       //(RTC-11b)
        lcd.setCursor(0,1);                      //(RTC-11c)
        lcd.print(“from RTC Chip       “);       //(RTC-11d)
        lcd.setCursor(0,3);                      //(RTC-11e)
        lcd.print(“                    “);       //(RTC-11f)
      }
      read_kbd();                                //(RTC-12)
      delay(100);                                //(RTC-13)
      if (active_key == 0x0D && i2c_answer == 0) //(RTC-14)
      {
      rtc_setup();                               //(RTC-15)
      lcd.setCursor(0,2);                        //(RTC-16a)
      lcd.print(“                    “);         //(RTC-16b)
      lcd.setCursor(17,3);                       //(RTC-16c)
      lcd.print(“(D)”);                          //(RTC-16d)
      }
   }
   gv_refresh = 1;                               //(RTC-17)
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------

执行步骤如下:
1. (RTC - 1至RTC - 3)清理显示并显示静态文本。
2. (RTC - 4)等待按键释放。
3. (RTC - 5)主循环运行直到按下星号键。
4. (RTC - 7)调用函数读取DS1307芯片的日期和时间信息。
5. (RTC - 8)若有响应,(RTC - 9)显示信息;若无响应,(RTC - 10至RTC - 11f)显示提示信息。
6. (RTC - 12)读取键盘输入。
7. (RTC - 14)若按下“D”键且有响应,(RTC - 15)调用 rtc_setup() 函数调整日期和时间。

5.3 RTC日期时间计算函数

w_date_time(byte w_col) 函数根据DS1307芯片的日期格式计算并显示日期和时间:

// --------------------------------------------------------------------
// --------------------------------------------------------------------
void w_date_time(byte w_col)
{
  rtc_day = ( ( rtc_day & 0b11110000 ) / 16 ) * 10 + ( rtc_day & 0b00001111 );
  rtc_mnt = ( ( rtc_mnt & 0b11110000 ) / 16 ) * 10 + ( rtc_mnt & 0b00001111 );
  rtc_year = ( ( rtc_year & 0b11110000 ) / 16 ) * 10 + ( rtc_year & 0b00001111 );
  rtc_year = rtc_year + 2000;

  lcd.setCursor(6,0);
  w_print_dec01_wlz(rtc_day);
  lcd.print(“.”);
  w_print_dec01_wlz(rtc_mnt);
  lcd.print(“.”);
  lcd.print(rtc_year);
  calc_day();
  lcd.setCursor(6,1);
  w_week_day(0);
  lcd.print(“   “);
  lcd.setCursor(6,w_col);
  rtc_hrs = ( ( rtc_hrs & 0b00110000 ) / 16 ) * 10 + ( rtc_hrs & 0b00001111 );
  w_print_dec01_wlz(rtc_hrs);
  lcd.print(“:”);
  rtc_min = ( ( rtc_min & 0b01110000 ) / 16 ) * 10 + ( rtc_min & 0b00001111 );
  w_print_dec01_wlz(rtc_min);
  lcd.print(“:”);
  rtc_sec = ( ( rtc_sec & 0b01110000 ) / 16 ) * 10 + ( rtc_sec & 0b00001111 );
  w_print_dec01_wlz(rtc_sec);
}
// --------------------------------------------------------------------
5.4 RTC星期显示函数

w_week_day(byte i_language) 函数根据 rtc_wday 变量显示星期几:

// --------------------------------------------------------------------
// --- write day in a week
// --------------------------------------------------------------------
void w_week_day(byte i_language)
{
   switch(rtc_wday)
     {
      case 1:
         lcd.print(“Monday”);
         break;
      case 2:
         lcd.print(“Tuesday”);
         break;
      case 3:
         lcd.print(“Wednesday”);
         break;
      case 4:
         lcd.print(“Thursday”);
         break;
      case 5:
         lcd.print(“Friday”);
         break;
      case 6:
         lcd.print(“Saturday”);
         break;
      case 0:
         lcd.print(“Sunday”);
         break;
     }
}
// --------------------------------------------------------------------
5.5 RTC I2C通信函数

i2c_rtc_read() 函数从DS1307芯片读取日期和时间信息:

// --------------------------------------------------------------------
// --- I2C RTC Read ---------------------------------------------------
// --------------------------------------------------------------------
void i2c_rtc_read()                        //(RR-1)
{
   Wire.beginTransmission(0b01101000);     //(RR-2)
   Wire.write(0x00);                       //(RR-3)
   i2c_answer = Wire.endTransmission(1);   //(RR-4)

   Wire.requestFrom(0b01101000, 7, 1);    //(RR-5) I2C address / 2 bytes // stop
   rtc_sec = Wire.read();                 //(RR-6a) read seconds
   rtc_min = Wire.read();                 //(RR-6b) read minutes
   rtc_hrs = Wire.read();                 //(RR-6c) read hours
   rtc_day = Wire.read();                 //(RR-6d) dummy read (day of a week)
   rtc_day = Wire.read();                 //(RR-6e) read calendar day
   rtc_mnt = Wire.read();                 //(RR-6f) read month
   rtc_year = Wire.read();                //(RR-6g) read year
}
// --------------------------------------------------------------------

执行步骤:
1. (RR - 2至RR - 4)向芯片发送起始读取地址00h。
2. (RR - 5)从芯片读取7字节数据。
3. (RR - 6a至RR - 6g)依次读取秒、分、时、日、月、年信息。

i2c_rtc_write() 函数将设置后的日期和时间写回DS1307芯片:

// --------------------------------------------------------------------
// --- I2C RTC Write --------------------------------------------------
// --------------------------------------------------------------------
void i2c_rtc_write()                                //(RW-1)
{
   rtc_sec = (rtc_sec/10)*16 + (rtc_sec%10);        //(RW-2a)
   rtc_min = (rtc_min/10)*16 + (rtc_min%10);        //(RW-2b)
   rtc_hrs = (rtc_hrs/10)*16 + (rtc_hrs%10);        //(RW-2c)
   rtc_day = (rtc_day/10)*16 + (rtc_day%10);        //(RW-2d)
   rtc_mnt = (rtc_mnt/10)*16 + (rtc_mnt%10);        //(RW-2e)
   rtc_year = rtc_year - 2000;                      //(RW-2f)
   rtc_year = (rtc_year/10)*16 + (rtc_year%10);     //(RW-2g)

   Wire.beginTransmission(0b01101000);              //(RW-3)
   Wire.write(0x00);                                //(RW-4)
   Wire.write(rtc_sec);                             //(RW-5a)
   Wire.write(rtc_min);                             //(RW-5b)
   Wire.write(rtc_hrs);                             //(RW-5c)
   Wire.write(rtc_wday);                            //(RW-5d)
   Wire.write(rtc_day);                             //(RW-5e)
   Wire.write(rtc_mnt);                             //(RW-5f)
   Wire.write(rtc_year);                            //(RW-5g)
   i2c_answer = Wire.endTransmission(1);            //(RW-6)
}
// --------------------------------------------------------------------

执行步骤:
1. (RW - 2x)将日期和时间信息转换为DS1307格式。
2. (RW - 3)启动I2C写模式通信。
3. (RW - 4)写入起始操作地址。
4. (RW - 5x)发送7字节日期和时间信息。
5. (RW - 6)结束I2C通信。

6. 星期计算(Calculation of a Weekday)

为避免使用RTC芯片的星期计数器(其仅为简单的3位计数器,与日期无关联且需手动设置),采用公式计算星期几。公式如下:
[w = (d + (2.6 \times m - 0.2) + y + (y / 4) + (c / 4) - 2 \times c) \mod 7]
其中各变量含义如下:
|变量|含义|
|----|----|
|w|星期几结果,对应关系:0 - 周日,1 - 周一,2 - 周二,3 - 周三,4 - 周四,5 - 周五,6 - 周六|
|d|月内日期,范围1 - 31|
|m|月份变量,编码如下:|
| |月份:March - 1,April - 2,Mai - 3,June - 4,July - 5,August - 6,September - 7,October - 8,November - 9,December - 10,January - 11,February - 12|
|y|年份变量1,3 - 12月为年份后两位,1 - 2月为前一年份后两位|
|c|年份变量2,3 - 12月为年份前两位,1 - 2月为前一年份前两位|

calc_day() 函数实现了该公式的计算:

// --------------------------------------------------------------------
// --------------------------------------------------------------------
// --- Calculation of week day; only if date > 2000
//     https://de.wikipedia.org/wiki/Wochentagsberechnung
// --------------------------------------------------------------------
// --------------------------------------------------------------------
void calc_day()
{
  byte cd_d;                          //(DW-1a) – variable “d”
  byte cd_m;                          //(DW-1b) – variable “m”
  byte cd_y;                          //(DW-1c) – variable “y”
  byte cd_c;                          //(DW-1d) – variable “c”
  word cd_help1;                      //(DW-1e)
  byte cd_help2;                      //(DW-1f)
  byte cd_help3;                      //(DW-1g)
  float cd_w_w2;                      //(DW-1h) – variable “w”
  cd_d = rtc_day;                     //(DW-2) – calculate variable “d”
  cd_m = rtc_mnt - 2;                 //(DW-3a) – calculate variable “m”
  if (rtc_mnt == 1) cd_m = 11;        //(DW-3b) – calculate variable “m” – for January
  if (rtc_mnt == 2) cd_m = 12;        //(DW-3c) – calculate variable “m” – for February
  cd_y = rtc_year - 2000;             //(DW-4a) – calculate variable “y”
  if (rtc_mnt < 3) cd_y = cd_y - 1;   //(DW-4b) – adjust variable “y” – for January and February
  cd_c = 20;                          //(DW-5a) – calculate variable “c”
  if ((rtc_mnt < 3) && (rtc_year == 2000)) cd_c = cd_c - 1; //(DW-5b) – adjust variable “c” – January, February and year 2000
// -------------- formula implementation: part 1 ----------------------------
  cd_help1 = ((26 * cd_m) - 2) / 10;  //(DW-C1)
  cd_help2 = cd_y / 4;                //(DW-C2)
  cd_help3 = cd_c / 4;                //(DW-C3)
// -------------- formula implementation: part 2 ----------------------------
  cd_w_w2 = (cd_d + cd_help1 + cd_y + cd_help2 + cd_help3 - 2 * cd_c) % 7;  //(DW-C4a)
  if (cd_w_w2 < 0) cd_w_w2 = 7 + cd_w_w2;                                   //(DW-C4b)
  rtc_wday = cd_w_w2;                //(DW-5)
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------

执行步骤:
1. (DW - 1x)声明局部变量。
2. (DW - 2)计算变量 d
3. (DW - 3x)计算变量 m
4. (DW - 4x)计算变量 y
5. (DW - 5x)计算变量 c
6. (DW - C1至DW - C3)计算部分结果。
7. (DW - C4a至DW - C4b)计算最终结果并处理负数情况。
8. (DW - 5)将结果赋值给 rtc_wday

整个MSP430微控制器应用程序通过上述各个函数的协同工作,实现了温度、湿度、日期时间的测量与显示,以及星期的准确计算,为用户提供了一个功能丰富且稳定的应用系统。

MSP430微控制器应用功能详解

7. 功能调用流程总结

为了更清晰地理解整个应用程序的功能调用流程,下面通过mermaid流程图展示主要函数之间的调用关系:

graph TD;
    A[setup()] --> B[loop()];
    B --> C[entry_main()];
    C --> D[main_app()];
    C --> E[i2c_temp_1()];
    C --> F[i2c_datum_1()];
    C --> G[hyt939()];
    D --> H[i2c_rtc_read()];
    D --> I[hyt939_start()];
    D --> J[find_i2c_temp()];
    F --> K[w_date_time()];
    F --> L[rtc_setup()];
    H --> M[w_date_time()];
    I --> N[hyt939_read()];
    J --> O[Wire相关操作];

从流程图可以看出,程序从 setup() 函数开始初始化,然后进入 loop() 主循环,在主循环中调用 entry_main() 进行功能选择。 entry_main() 可以调用不同的功能函数,如 main_app() i2c_temp_1() i2c_datum_1() hyt939() main_app() 函数内部又会调用多个子函数来完成数据的采集和显示。

8. 关键代码逻辑分析
8.1 温度显示稳定性逻辑

在温度测量部分,有一段代码用于确保温度显示的稳定性:

if(temp_lsb_old == 0xFE)             //(MA-23-08)
{
    v_temp_lsb = temp_lsb_new;        //(MA-23-09)
    temp_lsb_old = temp_lsb_new;      //(MA-23-10)
    lv_c1 = 0;                        //(MA-23-11)
}
if(temp_lsb_new != temp_lsb_old) lv_c1++; //(MA-23-12)
else lv_c1 = 0;                      //(MA-23-13)
if(lv_c1 == 3)                       //(MA-23-14)
{
    v_temp_lsb = temp_lsb_new;        //(MA-23-15)
    temp_lsb_old = temp_lsb_new;      //(MA-23-16)
    lv_c1 = 0;                        //(MA-23-17)
}

这段代码的逻辑是:当首次读取温度时,将新的温度低位字节赋值给旧的温度低位字节,并将计数器 lv_c1 置为0。之后每次读取,如果新的温度低位字节与旧的不同,计数器 lv_c1 加1;如果相同,则将计数器置为0。只有当计数器 lv_c1 达到3时,才更新显示的温度值,这样可以避免因测量误差导致的温度显示频繁跳动。

8.2 RTC日期时间格式转换

w_date_time() 函数中,有一系列代码用于将DS1307芯片存储的日期时间格式转换为人类可读的格式:

rtc_day = ( ( rtc_day & 0b11110000 ) / 16 ) * 10 + ( rtc_day & 0b00001111 );
rtc_mnt = ( ( rtc_mnt & 0b11110000 ) / 16 ) * 10 + ( rtc_mnt & 0b00001111 );
rtc_year = ( ( rtc_year & 0b11110000 ) / 16 ) * 10 + ( rtc_year & 0b00001111 );
rtc_year = rtc_year + 2000;

这里使用了位运算和数学运算,将DS1307芯片以BCD码(二进制编码的十进制数)存储的日期时间转换为十进制数。例如,对于日期 rtc_day (rtc_day & 0b11110000) / 16 提取出十位数字, rtc_day & 0b00001111 提取出个位数字,然后将它们组合成十进制数。最后,将年份加上2000年份前缀,得到完整的年份。

9. 代码优化建议
9.1 错误处理优化

在与传感器通信的过程中,目前仅通过 i2c_answer 判断是否有响应,但没有详细的错误信息输出。可以添加更多日志输出,方便测试和调试。例如,在 i2c_rtc_read() 函数中:

void i2c_rtc_read()
{
    Wire.beginTransmission(0b01101000);
    Wire.write(0x00);
    i2c_answer = Wire.endTransmission(1);
    if (i2c_answer != 0) {
        // 输出错误信息,如错误码等
        Serial.print("RTC read error: ");
        Serial.println(i2c_answer);
    }
    Wire.requestFrom(0b01101000, 7, 1);
    // 后续读取操作
}
9.2 代码复用优化

部分代码存在重复,如 lcd.setCursor() lcd.print() 操作。可以将这些重复的代码封装成函数,提高代码的复用性。例如,将显示日期时间的代码封装成一个独立的函数:

void displayDateTime()
{
    lcd.setCursor(6,0);
    w_print_dec01_wlz(rtc_day);
    lcd.print(“.”);
    w_print_dec01_wlz(rtc_mnt);
    lcd.print(“.”);
    lcd.print(rtc_year);
    // 后续显示操作
}

然后在需要显示日期时间的地方调用该函数。

10. 总结

本文详细介绍了MSP430微控制器应用程序的各个功能模块,包括初始化设置、主循环、功能选择、主应用程序、RTC相关功能和星期计算等。通过对每个功能模块的代码分析和操作步骤说明,我们了解了温度、湿度、日期时间的测量与显示,以及星期的准确计算是如何实现的。同时,通过流程图展示了主要函数之间的调用关系,使功能调用流程更加清晰直观。最后,提出了一些代码优化建议,如错误处理优化和代码复用优化,以提高程序的健壮性和可维护性。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值