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相关功能和星期计算等。通过对每个功能模块的代码分析和操作步骤说明,我们了解了温度、湿度、日期时间的测量与显示,以及星期的准确计算是如何实现的。同时,通过流程图展示了主要函数之间的调用关系,使功能调用流程更加清晰直观。最后,提出了一些代码优化建议,如错误处理优化和代码复用优化,以提高程序的健壮性和可维护性。
超级会员免费看

被折叠的 条评论
为什么被折叠?



