当前位置:网站首页>嵌入式设计与开发项目-液位检测告警系统
嵌入式设计与开发项目-液位检测告警系统
2022-06-28 13:20:00 【程序小鹿】
嵌入式设计与开发项目-液位检测告警系统
一、实现的功能
- ①液位检测,通过ADC外设检测电位器的电压模拟液位传感器,并通过公式计算出液位高度;
- ②阈值设置,通过按键外设设置液位的阈值;
- ③阈值保存,通过IIC外设把数据保存到AT12C02存储器中;
- ④串口的查询和输出,通过串口外设发送特定的字符‘C’、‘S’分别查询液位高度和等级以及阈值。液位等级改变时串口发送实时液位数据;
- ⑤状态指示,通过LED外设的LD1以1S间隔闪烁表示运行状态指示灯,LD2以0.2S间隔闪烁5次表示液位等级发送变化,LD3以0.2S间隔闪烁5次表示串口接收到信息;
二、根据功能实现代码
1、主文件main.c
#include "stm32f10x.h"
#include "lcd.h"
#include "led.h"
#include "key.h"
#include "usart.h"
#include "i2c.h"
#include "adc.h"
typedef unsigned char uchar;
typedef unsigned int uint;
uint uiAdc_Val; //R37模拟液位传感器的ADC值
uchar ucHeight,ucLevel,ucLevel1; //液位高度、液位等级
uchar ucState,pucStr[21],pucTh[3],pucRcv[1]; //LCD显示缓冲区、液位阈值、串口缓冲区
uchar ucLed,ucLd2,ucLd3,ucNum = 10; //点亮LED
uchar ucSec,ucSec1,ucKey_Long; //保存ms、s,长按标志位
unsigned long ulTick_ms; //滴答定时器的计数
void KEY_Proc(void);
void LCD_Proc(void);
void ADC_Proc(void);
void UART_Proc(void);
//Main Body
int main(void)
{
SysTick_Config(SystemCoreClock/1000); //设置系统滴答时钟1ms并使能中断
KEY_Init(); //按键初始化
LED_Init(); //LED初始化
STM3210B_LCD_Init(); //LCD初始化
LCD_Clear(Blue); //把屏幕刷新为蓝色
LCD_SetBackColor(Blue); //设置字体背景为蓝色
LCD_SetTextColor(White); //字体设置为白色
USART2_Init(9600); //串口初始化
i2c_init(); //IIC初始化
ADC1_Init(); //ADC初始化
i2c_read(pucTh,0,3); //AT24C02读取从地址0开始的3个字节的数据
if(pucTh[0] > 100)
pucTh[0] = 10;
if(pucTh[1] > 100)
pucTh[0] = 20;
if(pucTh[2] > 100)
pucTh[0] = 30;
while(1)
{
KEY_Proc(); //按键相对应的功能
LCD_Proc(); //LCD相对应的功能
ADC_Proc(); //ADC采集相对应的功能
UART_Proc(); //串口相对应的功能
}
}
/********************************************************************************************** *函数:void KEY_Proc(void) *功能:按键B1设置键,B2切换键,B3加键,B4减键 *输入:无 *输出:无 *特殊说明:各按键互不影响 **********************************************************************************************/
void KEY_Proc(void)
{
uchar ucKey_Val;
ucKey_Val = KEY_Scan(); //检测那个按键按下
if(ucKey_Val != ucKey_Long)
ucKey_Long = ucKey_Val;
else
ucKey_Val = 0; //防止长按
switch(ucKey_Val)
{
case 1: //B1:设置键
if(!ucState)
ucState = 1;
else
{
if((pucTh[0]) < pucTh[1] && pucTh[1] < pucTh[2])
{
LCD_DisplayStringLine(Line3,(u8*)" ");
i2c_write(pucTh , 0 , 3); //pucTh阈值存到AT24C02
ucState = 0;
}
else
{
LCD_SetTextColor(Red);
LCD_DisplayStringLine(Line3,(u8*)" Threshold Error "); //设置阈值有误
LCD_SetTextColor(White);
}
}
break;
case 2: //B2:切换键
if(ucState)
if(++ucState == 4)
ucState = 1;
break;
case 3: //B3:阈值加
if(ucState)
if(pucTh[ucState-1] < 95)
pucTh[ucState-1] +=5;
break;
case 4: //B3:阈值减
if(ucState)
if(pucTh[ucState-1] > 5)
pucTh[ucState-1] -=5;
break;
}
}
/********************************************************************************************** *函数:void LCD_Proc(void) *功能:LCD屏幕显示函数 *输入:无 *输出:无 *特殊说明:无 **********************************************************************************************/
void LCD_Proc(void)
{
float temp;
if(!ucState) //0显示状态界面,不等于0显示设置界面
{
LCD_DisplayStringLine(Line1,(u8*)" Liquid Level ");
sprintf((char*)pucStr," Height:%03ucm ",ucHeight);
LCD_DisplayStringLine(Line4,pucStr);
temp = (float)uiAdc_Val * 3.3 /4095;
sprintf((char*)pucStr," VR37: %4.3fV ",temp);
LCD_DisplayStringLine(Line6,pucStr);
sprintf((char*)pucStr," Level: %01u ",ucLevel);
LCD_DisplayStringLine(Line8,pucStr);
}
else
{
LCD_DisplayStringLine(Line1,(u8*)" Threshold Setup ");
//索引在第1个阈值设置
sprintf((char*)pucStr," Threshold 1: %02ucm ",pucTh[0]);
if(ucState == 1)
LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line4,pucStr);
LCD_SetBackColor(Blue);
//索引在第2个阈值设置
sprintf((char*)pucStr," Threshold 2: %02ucm ",pucTh[1]);
if(ucState == 2)
LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line6,pucStr);
LCD_SetBackColor(Blue);
//索引在第3个阈值设置
sprintf((char*)pucStr," Threshold 3: %02ucm ",pucTh[2]);
if(ucState == 3)
LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line8,pucStr);
LCD_SetBackColor(Blue);
}
}
/********************************************************************************************** *函数:void ADC_Proc(void) *功能:ADC采集电位器R37的电压信号 *输入:无 *输出:无 *特殊说明:无 **********************************************************************************************/
void ADC_Proc(void)
{
if(!ucState && ucSec != ucSec1)
{
ucSec1 = ucSec;
uiAdc_Val = ADC1_Conv(); //获取装换值
ucHeight = uiAdc_Val*100/4095; //计算液位高度 ADC_Val = V * 4095 / 3.3
if(ucHeight < pucTh[0])
ucLevel = 0;
else if(ucHeight < pucTh[1])
ucLevel = 1;
else if(ucHeight < pucTh[2])
ucLevel = 2;
else
ucLevel = 3;
if(ucLevel != ucLevel1)
{
if(ucLevel > ucLevel1) //液位升高
printf("A:H%02u+L%01u+U\r\n",ucHeight,ucLevel);
else //液位减低
printf("A:H%02u+L%01u+D\r\n",ucHeight,ucLevel);
ucLevel1 = ucLevel;
ucLd2 = 1; //等级改变
}
}
}
/********************************************************************************************** *函数:void UART_Proc(void) *功能:串口查询与发送函数 *输入:无 *输出:无 *特殊说明:无 **********************************************************************************************/
void UART_Proc(void)
{
if(pucRcv[0] == 'C')
printf("C:H%02u+L%01u\r\n",ucHeight,ucLevel);
if(pucRcv[0] == 'S')
printf("S:TL%02u+TM%02u+TH%02u\r\n",pucTh[0],pucTh[1],pucTh[2]);
if(pucRcv[0] == 'C' || pucRcv[0] == 'S')
ucLd3 = 1; //串口查询
pucRcv[0] = 0;
}
/********************************************************************************************** *函数:void SysTick_Handler(void) *功能:滴答定时器中断函数 *输入:无 *输出:无 *特殊说明:每1模式进入一次 **********************************************************************************************/
void SysTick_Handler(void)
{
ulTick_ms++;
if(ulTick_ms%1000 == 0)
{
ucSec++;
ucLed ^=1; //LD1闪烁
}
if(ucLd2)
{
if(ulTick_ms%200 == 0)
{
if(ucNum--)
ucLed ^= 2; //LD2闪烁5次
else
{
ucLd2 = 0;
ucNum = 10;
}
}
}
if(ucLd3)
{
if(ulTick_ms%200 == 0)
{
if(ucNum--)
ucLed ^= 4; //LD3闪烁5次
else
{
ucLd3 = 0;
ucNum = 10;
}
}
}
LED_Disp(ucLed);
}
/********************************************************************************************** *函数:void USART2_IRQHandler( void ) *功能:接收串口2的数据 *输入:无 *输出:无 *特殊说明:接收串口2的中断服务函数 **********************************************************************************************/
void USART2_IRQHandler(void)
{
pucRcv[0] = USART_ReceiveData(USART2);
}
主函数分析:️ ️ ️
- 定义全局变量,在当前源文件的函数可以交叉赋值和使用。
- 主控芯片的每个外设尽量模块化,每个函数负责一个外设的功能。
- 定义了三个ucLevel1、ucSec1、ucKey_Long变量,分别保存上一次的液位等级、时间、按键键值,从而实时判断液位等级、延时1S、防止长按的功能。
2、void KEY_Proc(void)按键处理程序设计
/********************************************************************************************** *函数:void KEY_Proc(void) *功能:按键B1设置键,B2切换键,B3加键,B4减键 *输入:无 *输出:无 *特殊说明:各按键互不影响 **********************************************************************************************/
void KEY_Proc(void)
{
uchar ucKey_Val;
ucKey_Val = KEY_Scan(); //检测那个按键按下
if(ucKey_Val != ucKey_Long)
ucKey_Long = ucKey_Val;
else
ucKey_Val = 0; //防止长按
switch(ucKey_Val)
{
case 1: //B1:设置键
if(!ucState)
ucState = 1;
else
{
if((pucTh[0]) < pucTh[1] && pucTh[1] < pucTh[2])
{
LCD_DisplayStringLine(Line3,(u8*)" ");
i2c_write(pucTh , 0 , 3); //pucTh阈值存到AT24C02
ucState = 0;
}
else
{
LCD_SetTextColor(Red);
LCD_DisplayStringLine(Line3,(u8*)" Threshold Error "); //设置阈值有误
LCD_SetTextColor(White);
}
}
break;
case 2: //B2:切换键
if(ucState)
if(++ucState == 4)
ucState = 1;
break;
case 3: //B3:阈值加
if(ucState)
if(pucTh[ucState-1] < 95)
pucTh[ucState-1] +=5;
break;
case 4: //B3:阈值减
if(ucState)
if(pucTh[ucState-1] > 5)
pucTh[ucState-1] -=5;
break;
}
}
按键KEY简要分析:️ ️
- 定义ucKey_Long标志位,防止长按一直执行该按键的功能;
- 定义pucTh[3]数据可以进行函数i2c_write的(unsigned char*)传参,把数据按顺序存到AT24C02存储器中;
- 如果ucState大于0,判断是设置界面,从而可以执行切换键、阈值加、阈值减的操作。
- 巧妙地使用ucState判断当前切换选择的液位等级阈值设置,并可使用到阈值数组pucTh的设置。
3、LCD处理程序设计
/********************************************************************************************** *函数:void LCD_Proc(void) *功能:LCD屏幕显示函数 *输入:无 *输出:无 *特殊说明:无 **********************************************************************************************/
void LCD_Proc(void)
{
float temp;
if(!ucState) //0显示状态界面,不等于0显示设置界面
{
LCD_DisplayStringLine(Line1,(u8*)" Liquid Level ");
sprintf((char*)pucStr," Height:%03ucm ",ucHeight);
LCD_DisplayStringLine(Line4,pucStr);
temp = (float)uiAdc_Val * 3.3 /4095;
sprintf((char*)pucStr," VR37: %4.3fV ",temp);
LCD_DisplayStringLine(Line6,pucStr);
sprintf((char*)pucStr," Level: %01u ",ucLevel);
LCD_DisplayStringLine(Line8,pucStr);
}
else
{
LCD_DisplayStringLine(Line1,(u8*)" Threshold Setup ");
//索引在第1个阈值设置
sprintf((char*)pucStr," Threshold 1: %02ucm ",pucTh[0]);
if(ucState == 1)
LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line4,pucStr);
LCD_SetBackColor(Blue);
//索引在第2个阈值设置
sprintf((char*)pucStr," Threshold 2: %02ucm ",pucTh[1]);
if(ucState == 2)
LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line6,pucStr);
LCD_SetBackColor(Blue);
//索引在第3个阈值设置
sprintf((char*)pucStr," Threshold 3: %02ucm ",pucTh[2]);
if(ucState == 3)
LCD_SetBackColor(Red);
LCD_DisplayStringLine(Line8,pucStr);
LCD_SetBackColor(Blue);
}
}
LCD屏幕简要分析:️ ️
- 如果ucState为0,是液位状态显示界面,否则是设置界面。
- 巧妙使用空格重叠另一个界面显示数据;
5、ADC处理程序设计
/********************************************************************************************** *函数:void ADC_Proc(void) *功能:ADC采集电位器R37的电压信号 *输入:无 *输出:无 *特殊说明:无 **********************************************************************************************/
void ADC_Proc(void)
{
if(!ucState && ucSec != ucSec1)
{
ucSec1 = ucSec;
uiAdc_Val = ADC1_Conv(); //获取装换值
ucHeight = uiAdc_Val*100/4095; //计算液位高度 ADC_Val = V * 4095 / 3.3
if(ucHeight < pucTh[0])
ucLevel = 0;
else if(ucHeight < pucTh[1])
ucLevel = 1;
else if(ucHeight < pucTh[2])
ucLevel = 2;
else
ucLevel = 3;
if(ucLevel != ucLevel1)
{
if(ucLevel > ucLevel1) //液位升高
printf("A:H%02u+L%01u+U\r\n",ucHeight,ucLevel);
else //液位减低
printf("A:H%02u+L%01u+D\r\n",ucHeight,ucLevel);
ucLevel1 = ucLevel;
ucLd2 = 1; //等级改变
}
}
}
ADC模拟液位电压简要分析:️ ️
- 在液位显示界面,进行1S采集一次模拟液位电压电位器;
- 根据获取到的AD值进行公式转换为高度,判断高度在液位的那个阈值范围内,从而得知当前的液位等级;
- 通过ucLevel1判断液位等级是否发送改变,根据液位改变给串口发送相对应的消息,并进行Ld2的5次闪烁。
6、UART处理程序设计
/********************************************************************************************** *函数:void UART_Proc(void) *功能:串口查询与发送函数 *输入:无 *输出:无 *特殊说明:无 **********************************************************************************************/
void UART_Proc(void)
{
if(pucRcv[0] == 'C')
printf("C:H%02u+L%01u\r\n",ucHeight,ucLevel);
if(pucRcv[0] == 'S')
printf("S:TL%02u+TM%02u+TH%02u\r\n",pucTh[0],pucTh[1],pucTh[2]);
if(pucRcv[0] == 'C' || pucRcv[0] == 'S')
ucLd3 = 1; //串口查询
pucRcv[0] = 0;
}
串口UART简要分析:️ ️
- 判断串口接收到的字符,是否和系统设置参数一致,执行相对应的功能。
- 接收完之后,重新把pucRcv缓冲区恢复默认值。
7、LED处理程序设计
/********************************************************************************************** *函数:void SysTick_Handler(void) *功能:滴答定时器中断函数 *输入:无 *输出:无 *特殊说明:每1模式进入一次 **********************************************************************************************/
void SysTick_Handler(void)
{
ulTick_ms++;
if(ulTick_ms%1000 == 0)
{
ucSec++;
ucLed ^=1; //LD1闪烁
}
if(ucLd2)
{
if(ulTick_ms%200 == 0)
{
if(ucNum--)
ucLed ^= 2; //LD2闪烁5次
else
{
ucLd2 = 0;
ucNum = 10;
}
}
}
if(ucLd3)
{
if(ulTick_ms%200 == 0)
{
if(ucNum--)
ucLed ^= 4; //LD3闪烁5次
else
{
ucLd3 = 0;
ucNum = 10;
}
}
}
LED_Disp(ucLed);
}
系统滴答定时器简要分析:️ ️
- 设置了1ms,中断进入这个函数一次,实现精准的计时。
- 如果液位等级发送变化,则LD2闪烁5次;如果接收到串口的指令,则LD3进行闪烁5次,闪烁完后清除标志位。
8、USART2处理程序设计
/********************************************************************************************** *函数:void USART2_IRQHandler( void ) *功能:接收串口2的数据 *输入:无 *输出:无 *特殊说明:接收串口2的中断服务函数 **********************************************************************************************/
void USART2_IRQHandler(void)
{
pucRcv[0] = USART_ReceiveData(USART2);
}
简要分析:️ ️
- 串口中断函数,串口接收到数据进入中断把数据保存到pucRcv数组中。
三、实现功能过程的注意与学习点
1、注意点
①如何定义全局变量,使各个外设功能耦合在一起!
2、学习的知识点
- ①实现模块化编程,每个外设的功能单独定义一个函数;
- ②巧妙地定义一个数组,保存液位各个等级的阈值,还实现阈值的加减操作;
- ③学会定义标志位,判断当前状态是否发生改变,防止长按按键、液位等级变化检测等功能;
- ④实现串口的中断接收服务函数;
️ ️ ️ ️ ️ ️
边栏推荐
- 求职简历的书写技巧
- Fs7022 scheme series fs4059a dual two lithium battery series charging IC and protection IC
- 证券账户开户哪家的费率低 怎么办理开户最安全
- Online JSON to plaintext tool
- How to set auto format after saving code in vscade
- Arduino-ESP32闪存文件插件程序搭建和上传
- Rk3399 platform development series explanation (use part) pinctrl subsystem introduction - Video Introduction
- 真香啊!最全的 Pycharm 常用快捷键大全!
- Oracle 云基础设施扩展分布式云服务,为组织提供更高的灵活性和可控性
- 数据分析-启动子进化分析
猜你喜欢

Watermaker of the Flink core

Centos6.5 php+mysql MySQL library not found

Stm32f1 and stm32cubeide programming example - matrix keyboard driver

2. 01背包问题

真香啊!最全的 Pycharm 常用快捷键大全!

词云的可视化设计教程

Hubble database x a joint-stock commercial bank: upgrade the number management system of Guanzi, so that every RMB has an "ID card"

StackOverflow 2022数据库年度调查

scratch旅行相册 电子学会图形化编程scratch等级考试一级真题和答案解析2022年6月

4年用户数破亿,孙哥带领波场再创新高
随机推荐
[today in history] June 28: musk was born; Microsoft launches office 365; The inventor of Chua's circuit was born
plt. Usage of savefig() and save path
How about stock online account opening and account opening process? Is it safe to open a mobile account?
You must configure either the server or JDBC driver (via the ‘serverTimezone‘ configuration property
为什么越来越多的用户放弃 Swagger,选择Apifox
Copy 10 for one article! The top conference papers published in South Korea were exposed to be plagiarized, and the first author was "original sin"?
开源项目维权成功案例: Spug 开源运维平台成功维权
Fs7022 scheme series fs4059a dual two lithium battery series charging IC and protection IC
数据分析-启动子进化分析
同花顺上怎么进行开户啊, 安全吗
An idea plug-in that automatically generates unit tests, which improves the development efficiency by more than 70%!
投资98万美元的Saas项目失败了
Forecast and Analysis on market scale and development trend of China's operation and maintenance security products in 2022
泛海微FH511单片机IC方案小家电LED照明MCU丝印FH511
pytorch基础
Vscode shortcut key
G1垃圾收集器中重要的配置参数及其默认值
The press conference of Tencent cloud Database & CSDN engineer's ability lightweight certification is coming
Mysql database literacy, do you really know what a database is
海思35xx实现GT911触摸屏功能「建议收藏」