STM32單片機(jī)酒精檢測(cè)防酒駕系統(tǒng)酒精報(bào)警器(程序+原理圖+PCB+視頻講解)
程序編譯器:keil 5
編程語言:C語言
設(shè)計(jì)編號(hào):C0062
功能描述
本系統(tǒng)由STM32F103C8T6單片機(jī)核心板、酒精傳感器、LCD1602液晶顯示、蜂鳴器報(bào)警、按鍵控制及電源組成。
1、通過傳感器檢測(cè)傳感器實(shí)際值,并將傳感器實(shí)際值顯示在LCD1602液晶上;
2、感器檢測(cè)采用的是AD數(shù)據(jù)轉(zhuǎn)換,然后經(jīng)過運(yùn)算獲得的;
3、三個(gè)按鍵設(shè)置閾值,分別為設(shè)置鍵、設(shè)置+、設(shè)置-,其中設(shè)置+、設(shè)置-只有在設(shè)置模式下才能進(jìn)行操作;
4、在設(shè)置模式下,液晶有對(duì)應(yīng)的顯示標(biāo)志,設(shè)置閾值存儲(chǔ)到單片機(jī)Flash中,具有掉電不丟失,無需重新設(shè)置;
5、設(shè)置值與采集值實(shí)時(shí)對(duì)比,如果出現(xiàn)異常情況,蜂鳴器報(bào)警提醒。
原理圖
STM32系列處理器是意法半導(dǎo)體ST公司生產(chǎn)的一種基于ARM 7架構(gòu)的32位、支持實(shí)時(shí)仿真和跟蹤的微控制器。選擇此款控制芯片是因?yàn)楸鞠到y(tǒng)設(shè)計(jì)并非追求成本的最低或更小的功耗,而是在實(shí)現(xiàn)本設(shè)計(jì)功能的前提下能夠提供更豐富的接口和功能以便于設(shè)計(jì)實(shí)驗(yàn)系統(tǒng)各實(shí)驗(yàn)項(xiàng)目所需的外圍擴(kuò)展電路。此款控制芯片在完成單片機(jī)課程的學(xué)習(xí)后上手較為容易,在醫(yī)療器械中應(yīng)用廣泛,具有很好的學(xué)習(xí)、實(shí)驗(yàn)研究價(jià)值。
一、STM32的主要優(yōu)點(diǎn):
(1)使用ARM最新的、先進(jìn)架構(gòu)的Cortex-M3內(nèi)核
(2) 優(yōu)異的實(shí)時(shí)性能
(3) 杰出的功耗控制
(4) 出眾及創(chuàng)新的外設(shè)
(5) 最大程度的集成整合
(6) 易于開發(fā),可使產(chǎn)品快速將進(jìn)入市場(chǎng)
二、STM32——最佳的平臺(tái)選項(xiàng)
對(duì)于使用同一平臺(tái)進(jìn)行多個(gè)項(xiàng)目開發(fā)而言,STM32是最
佳的選擇:
(1) 從僅需少量的存儲(chǔ)空間和管腳應(yīng)用到需要更多的存儲(chǔ)空間和管腳的應(yīng)用
(2) 從苛求性能的應(yīng)用到電池供電的應(yīng)用
(3) 從簡(jiǎn)單而成本敏感的應(yīng)用到高端應(yīng)用
(4) 全系列腳對(duì)腳、外設(shè)及軟件的高度兼容性,給您帶來全方位的靈活性。您可以在不必修改您原始框架及軟件的條件下,將您的應(yīng)用升級(jí)到需要更多存儲(chǔ)空間或精簡(jiǎn)到使用更少存儲(chǔ)空間/ 或改用不同的封裝的規(guī)格。
PCB
程序
main函數(shù)
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include <stdio.h>
#include "timer.h"
#include "key.h"
#include <stdio.h>
#include "lcd1602.h"
#include "adc.h"
#include "stmflash.h"
//#define BASICS_VAL 36 //用于數(shù)據(jù)轉(zhuǎn)換的基礎(chǔ)值
#define DEFAULT_SET_VAL 100 //第一次下載默認(rèn)設(shè)置值
char dis0[17]; //暫存數(shù)組
char dis1[17]; //暫存數(shù)組
unsigned int sensorVal = 0; //當(dāng)前采集值
unsigned int adcx;
long midData = 0;//中間變量
unsigned int setNum = DEFAULT_SET_VAL; //設(shè)置值
unsigned char setMode = 0;//默認(rèn)手動(dòng)模式
unsigned char disFlag = 0;//顯示標(biāo)志
#define FLASH_SAVE_ADDR 0X08010000 // 注意不同芯片 扇區(qū)flash地址不一樣 設(shè)置FLASH 保存地址(必須為偶數(shù),且其值要大于本代碼所占用FLASH的大小+0X08000000)
//stm32f103R8T6 flash地址范圍 0x8010000-0x801FFFF
//stm32f103C8T6 flash地址范圍 0x8000000-0x807FFFF
#define SIZE 10 //數(shù)組長度
unsigned char setFlashBuf[10];//存儲(chǔ)數(shù)據(jù)'
unsigned char initFlagData; //初始化數(shù)據(jù)存讀取
/******************把數(shù)據(jù)保存到單片機(jī)內(nèi)部eepom中******************/
void write_FlashBuf(void)
{
setFlashBuf[0] = initFlagData;
setFlashBuf[1] = setNum / 256; //重新寫入值
setFlashBuf[2] = setNum % 256;
STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)setFlashBuf,SIZE); //讀取數(shù)據(jù)
}
/******************把數(shù)據(jù)從單片機(jī)內(nèi)部eepom中讀出來*****************/
void read_FlashBuf(void)
{
STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)setFlashBuf,SIZE); //讀取flash值
initFlagData = setFlashBuf[0]; //數(shù)據(jù)初始化讀取
setNum = setFlashBuf[1]; //讀取高字節(jié)
setNum <<= 8;
setNum |= setFlashBuf[2]; //讀取低字節(jié) 并合并
}
/**************開機(jī)初始化保存的數(shù)據(jù)*****************/
void init_FlashBuf(void)
{
read_FlashBuf(); //讀取flash值
if(initFlagData != 0x55) //新的單片機(jī)初始單片機(jī)內(nèi)問eeprom 如果不是0x55重新寫入
{
setNum = DEFAULT_SET_VAL;//設(shè)置上限
initFlagData = 0x55; //修改值
delay_ms(20);
write_FlashBuf(); //讀取數(shù)據(jù)
}
}
void CheckKey(void);
int main(void)
{
delay_init(); //延時(shí)函數(shù)初始化
uart_init(9600); //串口初始化為115200
TIM3_Int_Init(499,7199); //定時(shí)器初始化
LED_Init(); //初始化接口
KEY_Init();
Adc_Init(); //初始化ad轉(zhuǎn)換
init_FlashBuf();//初始化讀取存儲(chǔ)數(shù)據(jù)
buzzer = 1; //蜂鳴器報(bào)警一下
delay_ms(200);
buzzer = 0;//蜂鳴器 停止報(bào)警
Lcd_GPIO_init(); //液晶接口初始化
Lcd_Init(); //液晶配置初始化
delay_ms(20);
while(1)
{
CheckKey(); //按鍵處理
if(disFlag==1)//定時(shí)讀取標(biāo)志
{
disFlag=0;//清空標(biāo)志
adcx=Get_Adc_Average(ADC_Channel_0,5);//讀取ad轉(zhuǎn)換值 5次求平均
midData = adcx * 450 * 2 / 4096; //讀取的ad值轉(zhuǎn)換
midData = midData - 250; //首先減去零點(diǎn)漂移,一般是1V
if(midData < 0)
midData = 0;
sensorVal = midData * 2; //將mV轉(zhuǎn)變成mg/L,系數(shù)需要校準(zhǔn)
//電壓每升高0.1V,實(shí)際被測(cè)氣體的濃度增加20ppm
//1ppm=1mg/kg=1mg/L=1×10-6 常用來表示氣體濃度,或者溶液濃度。
//以上根據(jù)手冊(cè)來的
sprintf(dis0,"nowValue:%03dmg/L",sensorVal); //打印
Lcd_Puts(0,0,(u8 *)dis0);//顯示
if(setMode){
sprintf(dis1,"setValue:%03d< ",setNum); //打印
}
else{
sprintf(dis1,"setValue:%03d ",setNum);
}
Lcd_Puts(0,1,dis1);//顯示
if(sensorVal > setNum) //采集值 和 設(shè)置值 對(duì)比
{buzzer = !buzzer;} //蜂鳴器報(bào)警
else {buzzer = 0;} //不報(bào)警
}
}
}
void CheckKey(void)
{
static unsigned char rekey =0;
if((key1==0)||(key2==0)||(key3==0)) //檢測(cè)到按鍵按下
{
delay_ms(10); //小抖動(dòng)
if(rekey==0)
{
if(key1==0) //檢測(cè)是否按下
{
rekey=1;
if(setMode){
setMode = 0; //取消設(shè)置
}
else {
setMode = 1; //設(shè)置狀態(tài)
}
}
else if(key2==0)//設(shè)置值鍵
{
rekey=1;
if(setMode){ //設(shè)置條件下
if(setNum < 999 ){setNum=setNum+1;} //+1
}
}
else if(key3==0)//設(shè)置值鍵
{
rekey=1;
if(setMode){ //設(shè)置條件下
if(setNum > 0 ){setNum=setNum-1;}
}
}
write_FlashBuf();//存儲(chǔ)數(shù)據(jù)
}
}
else
{
rekey=0; //防止重復(fù)檢測(cè)到按鍵
}
}