本课程的主要目的是学习MSPM0L1306的ADC应用和DS18B20温度传感器单线协议。
本次学习实现按键报警,ADC-NTC温度采集,DS18B20温度传感器单线通讯以及温度显示及环境温差异常报警。
一、硬件学习
1、按键。
S1按键:PA18默认外部下拉,检测高电平有效,配置IO时需要内部下拉或悬空。课程1中有介绍,参考:
https://forum.eepw.com.cn/thread/381478/1
2、蜂鸣器。
本次使用蜂鸣器为低电平触发方式,IO使用PA6口,配置IO时需要内部上拉或悬空,硬件原理如下:

3、ADC热敏电阻。
由开发板原理图可以看出,NTC温度传感器接至了ADC通道9(PA15),如下:

NTC使用型号为TI的TMP6161DECT,其为正温度系数热敏电阻。详细规格可在TI官网中找到,链接如下:
使用热敏电阻,自然离不开其温度-电阻值数据表,通过规格书可直接找到其设计工具表。


点击Thermistor Design Tool (zip)下载,得到两个Excel表:

开发板热敏电阻接法为电压基准方式,固查看电压基准的Excel文档即可。(电流基准方式可自行学习)

文档中直接给出了温度/电阻值对应关系表。本次学习使用1℃档位的电阻值分压关系,通过ADC采样的AD值查表,得到对应NTC温度值。
原理图中,NTC接法:3.3V供电,电阻10K/NTC(10K)。
得出ADC电压关系为:Uadc = 3.3*RT/(10000+RT);
转换为ADC(12bit)采样AD值为:AD = Uadc*4096/3.3 = 4096*RT/(10000+RT)。
由此ADC采样获得AD值,通过AD/RT和RT/℃的对应关系,可通过查表方式得到AD值对应温度。温度/AD表和查询函数如下:

4、数码管显示器。
在课程2中,已对数码管显示器做了详细介绍,参考:
https://forum.eepw.com.cn/thread/381492/1
由于本次课程中使用了S1按键(PA18)和ADC通道9(PA15),固在课程2的基础上调整一下显示器接口:PA21-->DIO,PA16-->SCLK,PA17-->RCLK。
5、DS18B20温度传感器。
本次使用通信IO为PA11,由于开发板缺少了3V3,固将SW2接口飞线至了3V3,SW1跳线帽接至PA11。
DS18B20为单线通信方式,原理很简单,具体可参考大神作品:
https://forum.eepw.com.cn/thread/381543/1

6、总体接线图。


二、软件配置
1、按键。

2、蜂鸣器。

3、ADC通道9。



4、数码管显示器。

依次修改:DAT-->PA21,CLK-->PA16,RCK-->PA17。
5、DS18B20温度传感器。

6、配置好sysconfig后,编译更新代码。

三、代码实现
1、基础代码:按键、蜂鸣器、HC595配置和相关参数。
#define Key1Tmp DL_GPIO_readPins(USER_KEYS_PORT, USER_KEYS_KEY1_PIN) //KEY1
#define BEEP_ON DL_GPIO_clearPins(BEEP_PORT, BEEP_PIN6_PIN); //Beep ON
#define BEEP_OFF DL_GPIO_setPins(BEEP_PORT, BEEP_PIN6_PIN); //Beep OFF
#define HC595_DAT_H DL_GPIO_setPins(HC595_PORT, HC595_DAT_PIN) //HC595 data
#define HC595_DAT_L DL_GPIO_clearPins(HC595_PORT, HC595_DAT_PIN)
#define HC595_CLK_H DL_GPIO_setPins(HC595_PORT, HC595_CLK_PIN) //HC595 sclk
#define HC595_CLK_L DL_GPIO_clearPins(HC595_PORT, HC595_CLK_PIN)
#define HC595_RCK_H DL_GPIO_setPins(HC595_PORT, HC595_RCK_PIN) //HC595 rclk
#define HC595_RCK_L DL_GPIO_clearPins(HC595_PORT, HC595_RCK_PIN)
volatile uint8_t Disp_DX[] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, //0 1 2 3 4 5 6 7 8 9
0x88, 0xA0, 0x83, 0xC6, 0xA7, 0xA1, 0x86, 0x8E, 0x8C, 0xFF, //A a b C c d E F P NC
0xBF, 0x7F, 0x9C, 0xA3, 0xC7, 0x89, 0xAB, 0xC1 }; //- . ^o^ o L H n U
volatile uint16_t KeyBounce=0;
//volatile uint16_t TmpVal3=0;
volatile bool gCheckADC;
volatile uint16_t gAdcResultVolts=0, gAdcNtcTempC=0, gDs18b20TempC=0, cycle=0;2、NTC热敏电阻查表函数。
//NTC Temperature: Divider resistance:10k/RT(TMP6131DECT), Vref:3.3V, -20~+100℃
volatile uint16_t NTC_AD[121] = { 1750, 1757, 1763, 1770, 1776, 1783, 1789, 1796, 1803, 1809,
1816, 1822, 1829, 1835, 1842, 1849, 1855, 1862, 1868, 1875,
1881, 1888, 1894, 1901, 1908, 1914, 1921, 1927, 1934, 1940,
1947, 1953, 1960, 1966, 1973, 1979, 1986, 1992, 1999, 2005,
2012, 2018, 2024, 2031, 2037, 2044, 2050, 2057, 2063, 2069,
2076, 2082, 2088, 2095, 2101, 2108, 2114, 2120, 2126, 2133,
2139, 2145, 2152, 2158, 2164, 2170, 2177, 2183, 2189, 2195,
2201, 2207, 2214, 2220, 2226, 2232, 2238, 2244, 2250, 2256,
2262, 2268, 2275, 2281, 2287, 2293, 2299, 2304, 2310, 2316,
2322, 2328, 2334, 2340, 2346, 2352, 2358, 2363, 2369, 2375,
2381, 2387, 2392, 2398, 2404, 2410, 2415, 2421, 2427, 2432,
2438, 2444, 2449, 2455, 2460, 2466, 2472, 2477, 2483, 2488,
2494 };
//NTC temperature AD value Search
int16_t NTC_AD_Search(uint16_t TempAD)
{
uint8_t start = 0;
uint8_t end = 120;
uint8_t mid = 0;
int16_t temp = 0;
uint16_t tmp;
while(start <= end)
{
mid = (start+end)/2;
if((TempAD >= NTC_AD[mid]) && (TempAD <= NTC_AD[mid+1]))
{
tmp = (TempAD - NTC_AD[mid]) << 1;
if(tmp >= (NTC_AD[mid+1] - NTC_AD[mid]))
mid = mid+1;
break;
}
else if((TempAD < NTC_AD[mid]) && (TempAD >= NTC_AD[mid-1]))
{
tmp = (NTC_AD[mid] - TempAD) << 1;
if(tmp > (NTC_AD[mid] - NTC_AD[mid-1]))
mid = mid-1;
break;
}
if(TempAD < NTC_AD[mid])
end = mid-1;
else if(TempAD > NTC_AD[mid])
start = mid+1;
}
temp = mid-20;
return temp;
}3、ADC中断回调和温度读取转换。
void ADC12_0_INST_IRQHandler(void)
{
switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST))
{
case DL_ADC12_IIDX_MEM0_RESULT_LOADED:
gCheckADC = true;
break;
default:
break;
}
}
void ReadNtcTemprature(void)
{
while (false == gCheckADC)
{
__WFE();
}
gAdcResultVolts = DL_ADC12_getMemResult(ADC12_0_INST, DL_ADC12_MEM_IDX_0);
gAdcNtcTempC = NTC_AD_Search(gAdcResultVolts);
gCheckADC = false;
}4、HC595显示函数。
//HC595 write 8bit
void HC595_WriteData(uint8_t data)
{
uint8_t i;
for(i=0; i<8; i++)
{
if((data & 0x80) > 0)
{
HC595_DAT_H;
}else
{
HC595_DAT_L;
}
data <<= 1;
HC595_CLK_L;
delay_cycles(8);
HC595_CLK_H;
delay_cycles(8);
}
}
//HC595 display enable
void Display_Out(void)
{
HC595_RCK_L;
delay_cycles(8);
HC595_RCK_H;
delay_cycles(8);
}
//HC595 write break and bit
void HC595_SendData(uint8_t disp_num, uint8_t disp_bit)
{
HC595_WriteData(disp_num);
HC595_WriteData(1 << disp_bit);
Display_Out();
}
//HC595 display 4 LEDs
void Display_4bData(uint16_t data)
{
uint16_t temp;
uint8_t num_q,num_b,num_s,num_g;
temp = data;
num_q = temp / 1000;
num_b = temp / 100 % 10;
num_s = temp / 10 % 10;
num_g = temp % 10;
HC595_SendData(Disp_DX[num_q],3);
HC595_SendData(Disp_DX[num_b],2);
HC595_SendData(Disp_DX[num_s],1);
HC595_SendData(Disp_DX[num_g],0);
}
//HC595 display 8 LEDs
void Display_8bData(uint16_t dataH, uint16_t dataL)
{
uint16_t tempH,tempL;
uint8_t num_q,num_b,num_s,num_g;
tempH = dataH;
num_q = tempH / 1000;
num_b = tempH / 100 % 10;
num_s = tempH / 10 % 10;
num_g = tempH % 10;
HC595_SendData(Disp_DX[num_q],7);
HC595_SendData(Disp_DX[num_b],6);
HC595_SendData(Disp_DX[num_s],5);
HC595_SendData(Disp_DX[num_g],4);
tempL = dataL;
num_q = tempL / 1000;
num_b = tempL / 100 % 10;
num_s = tempL / 10 % 10;
num_g = tempL % 10;
HC595_SendData(Disp_DX[num_q],3);
HC595_SendData(Disp_DX[num_b],2);
HC595_SendData(Disp_DX[num_s],1);
HC595_SendData(Disp_DX[num_g],0);
}
//HC595 display temperature: 3 integers, 1 decimal point: xxx.x
void Display_D3P1TempC(uint16_t data)
{
uint16_t temp;
uint8_t num_q,num_b,num_s,num_g;
temp = data;
num_q = temp / 1000;
num_b = temp / 100 % 10;
num_s = temp / 10 % 10;
num_g = temp % 10;
HC595_SendData(Disp_DX[num_q],3);
HC595_SendData(Disp_DX[num_b],2);
HC595_SendData(Disp_DX[num_s]&0x7F,1);
HC595_SendData(Disp_DX[num_g],0);
}
//HC595 display temperature: 3 integers + 2 integers, 1 decimal point: xxxC + xx.xC
void Display_AD3P1TempC(uint16_t dataH, int16_t dataL)
{
uint16_t tempH,tempL;
uint8_t num_q,num_b,num_s,num_g;
tempH = dataH;
num_b = tempH / 100 % 10;
num_s = tempH / 10 % 10;
num_g = tempH % 10;
if(num_b > 0)
HC595_SendData(Disp_DX[num_b],7);
HC595_SendData(Disp_DX[num_s],6);
HC595_SendData(Disp_DX[num_g],5);
HC595_SendData(Disp_DX[13],4);
tempL = dataL;
num_b = tempL / 100 % 10;
num_s = tempL / 10 % 10;
num_g = tempL % 10;
HC595_SendData(Disp_DX[num_b],3);
HC595_SendData(Disp_DX[num_s]&0x7F,2);
HC595_SendData(Disp_DX[num_g],1);
HC595_SendData(Disp_DX[13],0);
}5、DS18B20读写函数。
//delay n us
void delay_us(uint32_t nus)
{
delay_cycles(nus*32);
}
//DS18B20 Reset
void DS18B20_Reset(void)
{
DS18B20_OutPut_Mode;
DS18B20_DIO_OUT_L;
delay_us(750); //750us
DS18B20_DIO_OUT_H;
delay_us(15); //15us
}
//DS18B20 ACK: 0 - true, 1 - false
uint8_t DS18B20_Check(void)
{
uint8_t retry = 0;
uint8_t rval = 0;
while ((DS18B20_DIO_IN > 0) && (retry < 200)) //wait 200us
{
retry++;
delay_us(1);
}
if (retry >= 200)
{
rval = 1;
} else
{
retry = 0;
while (!(DS18B20_DIO_IN > 0) && (retry < 240)) //wait 240us
{
retry++;
delay_us(1);
}
if (retry >= 240) rval = 1;
}
return rval;
}
//DS18B20 Initialization
uint8_t DS18B20_Init(void)
{
DS18B20_Reset();
return DS18B20_Check();
}
//DS18B20 read 1bit
uint8_t DS18B20_Read_bit(void)
{
uint8_t data = 0;
DS18B20_DIO_OUT_L;
delay_us(2);
DS18B20_DIO_OUT_H;
delay_us(12);
DS18B20_InPut_Mode;
if (DS18B20_DIO_IN > 0)
{
data = 1;
}
delay_us(50);
return data;
}
//DS18B20 read 1Byte
uint8_t DS18B20_Read_Byte(void)
{
uint8_t i, b, data = 0;
for (i = 0; i < 8; i++)
{
b = DS18B20_Read_bit(); //LSB -> MSB
data |= b << i;
}
return data;
}
//DS18B20 write 1Byte
void DS18B20_Write_Byte(uint8_t data)
{
uint8_t j;
for (j = 1; j <= 8; j++)
{
if (data & 0x01)
{
DS18B20_DIO_OUT_L; //write 1
delay_us(2);
DS18B20_DIO_OUT_H;
delay_us(50);
} else
{
DS18B20_DIO_OUT_L; //write 0
delay_us(50);
DS18B20_DIO_OUT_H;
delay_us(2);
}
data >>= 1;
}
}
//DS18B20 start convert temperature
void DS18B20_Start(void)
{
DS18B20_Reset();
DS18B20_Check();
DS18B20_Write_Byte(0xcc); //skip rom
DS18B20_Write_Byte(0x44); //convert
}
//DS18B20 get temperature value, 0.1C ,return C = temp/10
uint16_t DS18B20_Get_Temperature(void)
{
uint8_t flag = 1; //Positive and Negative flag: Positive
uint8_t TempL, TempH;
uint16_t temp;
DS18B20_Start(); //DS18B20 start convert
DS18B20_Reset();
DS18B20_Check();
DS18B20_Write_Byte(0xcc); //skip rom
DS18B20_Write_Byte(0xbe); //convert
TempL = DS18B20_Read_Byte(); //LSB
TempH = DS18B20_Read_Byte(); //MSB
if (TempH > 7)
{
TempH = ~TempH;
TempL = ~TempL;
flag = 0; //Negative
}
temp = TempH;
temp <<= 8;
temp += TempL;
//convert temperature
if (flag == 0)
{
temp = (double)(temp+1) * 0.625;
temp = -temp;
} else
{
temp = (double)temp * 0.625;
}
return temp;
}6、main函数。
int main(void)
{
SYSCFG_DL_init();
NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN);
while (1)
{
if(Key1Tmp)
{
KeyBounce ++;
if(KeyBounce >= 2000)
{
//TmpVal3++;
KeyBounce = 0;
BEEP_ON;
}
//if(TmpVal3 >= 10000) TmpVal3 = 0;
}
else if(((float)gDs18b20TempC/10 - (float)gAdcNtcTempC) > 3.0) //DS18B20 temperature - NTC temperature > 3.0C
{
BEEP_ON;
}
else BEEP_OFF;
//Display_4bData(TmpVal3);
cycle++;
if(cycle >= 8000)
{
cycle = 0;
DL_ADC12_startConversion(ADC12_0_INST);
ReadNtcTemprature(); //get NTC temperature
DL_ADC12_enableConversions(ADC12_0_INST);
gDs18b20TempC = DS18B20_Get_Temperature(); //get DS18B20 temperature
}
Display_AD3P1TempC(gAdcNtcTempC, gDs18b20TempC); //display NTC & DS18B20 temperature
}
}四、显示效果

成果视频:
视频1:http://v.eepw.com.cn/video/play/id/15983
视频2:http://v.eepw.com.cn/video/play/id/15984
视频3:http://v.eepw.com.cn/video/play/id/15985
完结,共进!
我要赚赏金
