一、項目介紹
當(dāng)前介紹的項目是基于 STM32F103ZET6 系列 MCU 設(shè)計的數(shù)顯熱水器,通過顯示屏來顯示熱水器的溫度及其工作狀態(tài),通過 PT100 傳感器來檢測熱水器的溫度變化,并通過電加熱片實現(xiàn)加熱過程,以達(dá)到控制熱水器溫度的目的。
二、設(shè)計流程
2.1 硬件選型
2.2 軟件設(shè)計
(1)顯示屏
使用 OLED 顯示屏來顯示熱水器的溫度及其工作狀態(tài),通過 SPI 接口與 STM32 芯片進(jìn)行通訊。設(shè)計溫度值及其單位、熱水器工作狀態(tài)等。
(2)溫度傳感器
使用 PT100 溫度傳感器來檢測熱水器內(nèi)部溫度的變化,并將數(shù)據(jù)通過 ADC 轉(zhuǎn)換后,傳輸給 STM32 芯片,以實現(xiàn)對熱水器加熱過程的控制。
(3)電加熱片
使用電加熱片模擬熱水器加熱過程,通過繼電器控制電加熱片的通斷,以調(diào)節(jié)熱水器的溫度。
(4)控制系統(tǒng)
通過 STM32 芯片來實現(xiàn)對熱水器的控制,讀取溫度傳感器的數(shù)據(jù)。
三、代碼設(shè)計
3.1 OLED顯示屏
(1)SPI 接口初始化
需要對 STM32F103ZET6 的 SPI 接口進(jìn)行初始化配置,設(shè)置相關(guān)的時鐘和模式,使其能夠與 OLED 顯示屏進(jìn)行通訊。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); // 打開SPI3時鐘
SPI_InitTypeDef spi_init_type;
spi_init_type.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
spi_init_type.SPI_Mode = SPI_Mode_Master;
spi_init_type.SPI_DataSize = SPI_DataSize_8b;
spi_init_type.SPI_CPOL = SPI_CPOL_Low;
spi_init_type.SPI_CPHA = SPI_CPHA_1Edge;
spi_init_type.SPI_NSS = SPI_NSS_Soft;
spi_init_type.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; // 設(shè)置 SPI 時鐘頻率為 72 MHz / 32 = 2.25MHz
spi_init_type.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI3, &spi_init_type);
SPI_Cmd(SPI3, ENABLE);
(2)OLED 顯示屏初始化
以下是 OLED 顯示屏的初始化代碼:
void OLED_Init(void) {
GPIO_SetBits(GPIOB, GPIO_Pin_6); //RST SET
GPIO_ResetBits(GPIOB, GPIO_Pin_6); //RST RESET
GPIO_SetBits(GPIOB, GPIO_Pin_6); //RST SET
?
write_command(0xAE); // 關(guān)閉顯示
write_command(0xD5); // 設(shè)置時鐘分頻因子,震蕩頻率
write_command(0x80); // 分頻因子=1 ,震蕩頻率(fosc)=8MHz
write_command(0xA8); // 設(shè)置驅(qū)動路數(shù):MUX(復(fù)用方式)
write_command(0x1F); // 1/32 duty (0x0F~0x3F)
write_command(0xD3); // 設(shè)置顯示偏移
write_command(0x00); // 不偏移
write_command(0x40); // 設(shè)置顯示開始行[5:0], 對于設(shè)置了32行的液晶,
// 這里的值為0表示從0行開始顯示
write_command(0x8D); // 對比度設(shè)置
write_command(0x14); // AHB參考電壓256等分 移位[3:0]100[n,1/256]
write_command(0x20); // 水平方向上的尋址模式
write_command(0x00); // 垂直方向上的尋址模式
write_command(0xA1); // 設(shè)置段再映射
write_command(0xC0); // 設(shè)置COM掃描方向
write_command(0xDA); // 設(shè)置COM引腳硬件配置
write_command(0x12);
write_command(0x81); // 對比度設(shè)置
write_command(0xBF); // 設(shè)置電荷泵電壓
write_command(0xD9); // 設(shè)置預(yù)充電周期
write_command(0xF1);
write_command(0xDB); // 設(shè)置VCOMH電壓倍率
write_command(0x40);
write_command(0xAF); // 打開顯示
?
OLED_Clear(); // 清屏
}
(3)OLED 顯示函數(shù)
接下來編寫 OLED 顯示函數(shù),實現(xiàn)字符和數(shù)字的顯示功能。
void OLED_show_string(uint8_t x, uint8_t y, char *str) {
uint8_t i = 0;
while (str[i] != '') {
OLED_show_char(x, y + i * 8, str[i]);
++i;
}
}
?
void OLED_show_char(uint8_t x, uint8_t y, char ch) {
uint8_t c = ch - 32;
if (c >= 96) return;
uint8_t* buffer = (uint8_t*)oled_buffer;
uint8_t cx, cy;
for (cy = 0; cy < 8; cy++) {
uint8_t line = font[c][cy];
for (cx = 0; cx < 6; cx++) {
if (line & 0x1) {
buffer[(y + cy) * OLEDWIDTH + x + cx] = 1;
} else {
buffer[(y + cy) * OLEDWIDTH + x + cx] = 0;
}
line > >= 1;
}
}
OLED_Draw_Pixel(x + 6, y, 0);
OLED_Draw_Pixel(x + 6, y + 1, 0);
OLED_Draw_Pixel(x + 6, y + 6, 0);
OLED_Draw_Pixel(x + 6, y + 7, 0);
}
(4)結(jié)果顯示
在代碼中調(diào)用 OLED_show_string 函數(shù)和 OLED_show_char 函數(shù)顯示數(shù)值和字符。
OLED_Init();
OLED_Clear();
OLED_show_string(0, 0, "HELLO WORLD!");
OLED_show_string(0, 16, "TEMP:20 C");
3.2 測溫代碼
(1)引腳配置
需要對 STM32F103ZET6 的 IO 口進(jìn)行配置,將用于連接 PT100 溫度傳感器的引腳設(shè)置為輸入模式。
這里以 PA0 引腳作為 PT100 傳感器的連接口(即 PT100 三線連接中的 R3 端),代碼如下:
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉輸入模式
GPIO_Init(GPIOA, &GPIO_InitStructure);
(2)ADC 配置
接下來需要對 STM32F103ZET6 的 ADC 進(jìn)行初始化配置,使其能夠讀取 PT100 溫度傳感器輸出的電壓信號。
這里以 ADC1 通道5 作為讀取口,代碼如下:
ADC_InitTypeDef ADC_InitStructure;
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 設(shè)置 ADC 時鐘為 PCLK2 的 1/6
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 打開 ADC1 時鐘
ADC_DeInit(ADC1); // 初始化 ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 連續(xù)轉(zhuǎn)換模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE); // 開啟 ADC1
(3)溫度轉(zhuǎn)換函數(shù)
根據(jù) PT100 溫度傳感器輸出電壓與溫度的關(guān)系,可使用線性函數(shù)計算出溫度值。
轉(zhuǎn)換公式如下:
Rt = (Vref - Vpt) / Ipt // Rt 為 PT100 的阻值,Vref 為基準(zhǔn)電壓,Vpt 為 PT100 輸出電壓,Ipt 為 PT100 驅(qū)動電流
Temp = a * Rt + b // Temp 為溫度值,a 和 b 為經(jīng)過擬合后的系數(shù)
其中 Rt 的計算需要使用差分運算放大器進(jìn)行轉(zhuǎn)換,這里不再贅述。假設(shè)已經(jīng)得到 Rt 值,則溫度轉(zhuǎn)換函數(shù)代碼如下:
float PT100_Get_Temperature(float Rt)
{
float a = 3.9083e-3f, b = -5.775e-7f, R0 = 100.0f; // 根據(jù)實際數(shù)據(jù)進(jìn)行擬合得到 a、b 和 R0 的值
float Tem, delta;
delta = pow(Rt / R0, 2) + a * (Rt / R0) + b;
Tem = (delta > 0) ? (-R0*a + sqrt(delta)) / (2 * b) : 0;
return Tem;
}
(4)數(shù)據(jù)采集
根據(jù)差分放大器輸出的電壓值得到 PT100 溫度傳感器的阻值,再根據(jù)阻值計算出實際溫度,最后將溫度值通過串口打印出來。以下是數(shù)據(jù)采集代碼:
float ADC_Get_Voltage(void)
{
float voltage = 0;
uint16_t adc_val = 0;
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_239Cycles5); // 配置 ADC 通道5
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 使能軟件觸發(fā) ADC 轉(zhuǎn)換
while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // 等待轉(zhuǎn)換結(jié)束
adc_val = ADC_GetConversionValue(ADC1); // 讀取 ADC 轉(zhuǎn)換結(jié)果
voltage = (float)adc_val * 3.3f / 4096; // 計算基準(zhǔn)電壓
return voltage;
}
float PT100_Get_Rt(float Vpt)
{
float Rsource = 10e3f, Rpt = 100.0f; // Rsource 為差分放大器輸出電阻,Rpt 為 PT100 阻值
float Ipt = (3.3f - Vpt) / Rsource; // 計算 PT100 驅(qū)動電流
float Rt = (3.3f - Vpt) / Ipt; // 根據(jù)歐姆定律計算出 PT100 阻值
return Rt;
}
void USART1_Send_Float(float f)
{
char buf[32];
sprintf(buf, "%.1f
", f); // 轉(zhuǎn)換為字符串
while (*buf)
{
USART_SendData(USART1, *buf);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
buf++;
}
}
int main(void)
{
...
while (1)
{
float Vpt = ADC_Get_Voltage(); // 獲取差分放大器輸出電壓
float Rt = PT100_Get_Rt(Vpt); // 計算 PT100 阻值
float Temp = PT100_Get_Temperature(Rt); // 根據(jù)阻值計算溫度
USART1_Send_Float(Temp); // 將溫度值打印到串口
delay_ms(500);
}
...
}
審核編輯 黃宇
-
OLED
+關(guān)注
關(guān)注
119文章
6200瀏覽量
224215 -
STM32
+關(guān)注
關(guān)注
2270文章
10900瀏覽量
356046 -
熱水器
+關(guān)注
關(guān)注
5文章
217瀏覽量
27076 -
Pt100
+關(guān)注
關(guān)注
9文章
172瀏覽量
69134 -
STM32F103ZET6
+關(guān)注
關(guān)注
9文章
67瀏覽量
21129
發(fā)布評論請先 登錄
相關(guān)推薦
評論