(本篇博客有很多还没讲解很细致,先贴出代码,等有时间再进行注解)
“模拟液位检测告警系统”通过采集模拟电压信号计算液位高度,并根据用户设定的液位阈值执行报警动作,在液位等级发生变化时,通过串行通讯接口将液位信息发送到 PC 机。系统框图如图 1 所示:
设计任务及要求
1. 液位检测
通过电位器 R37 模拟液位传感器输出电压信号,设备以 1 秒为间隔采集 R37 输出电压,并与用户设定的液位阈值进行比较。假定液位高度与 R37 输出电压之间具有正比例关系:H = VR37*K,当 VR37=3.3V 时,对应液位高度为 100cm。通过液晶显示当前的液位高度、传感器(R37)输出状态和液位等级,液位检测显示界面如图 1 所示:
AD 采集得到的结果应经过软件滤波算法处理,显示结果保留小数点后两位有效数字
2. 液位阈值设定
设备可设定三个液位阈值,对应四个液位等级,阈值由用户通过按键输入,设备保存阈值,并根据此阈值判断液位等级,假 定用户输入的三个液位阈值为 10cm、20cm 和 30cm,液位高度与液位等级的对应关系如下:
2.1 液位高度≤10cm 时,液位等级为 0;
2.2 10cm<液位高度≤20cm 时,液位等级为 1;
2.3 20cm<液位高度≤30cm 时,液位等级为 2;
2.4 液位高度>30cm 时,液位等级为 3。
设备初始液位阈值分别为 30cm、50cm 和 70cm,用户修改阈值后,设备应将此参数保
存在 E2PROM 中,当设备重新上电时,可从 E2PROM 中获取。
3. 液位阈值设定
B1 按键:“设置”按键,按下后进入阈值设定界面(如图 2 所示),再次按下 B1 按键时退出设置界面,保存用户设定的结果到 E2PROM,并返回图 1 所示的液位检测界面。
B2 按键:切换选择 3 个待修改的阈值,被选中的阈值应突出显示。
B3 按键:“加”按键,按下后,被选择的阈值增加 5cm,增加到 95cm 为止。
B4 按键:“减”按键,按下后,被选择的阈值减少 5cm,减少到 5cm 为止。
4. 串口查询与输出功能
’ 使用 STM32 USART2 完成以下串口功能,波特率设置为 9600。
4.1 查询
通过 PC 机向设备发送字符‘C’,设备返回当前液位高度和液位等级;
通过 PC 机向设备发送字符‘S’,设备返回当前设定的三个阈值。
液位高度和等级返回数据格式举例:
“C:H55+L2\r\n”
解析:应答高度、等级查询,液位高度为 55cm,液位等级为 2。
阈值返回数据格式举例:
“S:TL30+TM50+TH70\r\n”
解析:应答阈值查询,设备内保存的三个阈值分别为 30cm、50cm 和 70cm。
4.2 输出
当液位等级发生变化时,设备自动向 PC 机发送当前液位等级、液位高度和液位变化趋势(上升或下降)。
输出数据格式举例:
“A:H55+L2+D\r\n”
解析:液位变化自动发送,液位高度 55cm,液位等级为 2,变化趋势下降。
“A:H55+L2+U\r\n”
解析:液位变化自动发送,液位高度 55cm,液位等级为 2,变化趋势上升。
5. 状态指示
LED 指示灯功能定义如下:
LD1:运行状态指示灯,以 1 秒为间隔亮灭闪烁;
LD2:液位等级变化指示灯,当液位等级发生变化时,LD2 以 0.2 秒为间隔闪烁 5 次;
LD3:通讯状态指示灯,当设备接收到查询指令时,LD3 以 0.2 秒为间隔闪烁 5 次
#include "stm32f10x.h"
#include "lcd.h"
#include "i2c.h"
#include "IO.h"
#include "stdio.h"
u32 TimingDelay = 0;
u8 string[20];
u8 ADC_Flag = 0;
u8 KEY_Flag = 0;
u8 LED_Flag = 0;
u8 Display_Flag = 0;
u8 Level_Last = 0;
u8 Shan2_sum = 0;
u8 Shan3_sum = 0;
float ADC_Val;
u8 Height;
u8 Threshold1 = 30;
u8 Threshold2 = 50;
u8 Threshold3 = 70;
u8 Level = 0;
u16 LED_MODE = 0XFFFF;
extern u8 RXCUNT;
extern u8 RXOVER;
extern u8 RX_BUF[20];
extern u8 Set_Flag;
extern u8 Threshold_Flag;
void Delay_Ms(u32 nTime);
u8 i;
u8 LD1_Flag = 0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
SysTick_Config(SystemCoreClock/1000);
i2c_init();
ADC1_Init();
USART2_Init(9600);
LED_Init();
KEY_Init();
Threshold1 = _24c02_Read(0x00);
Delay_Ms(5);
Threshold2 = _24c02_Read(0x01);
Delay_Ms(5);
Threshold3 = _24c02_Read(0x02);
Delay_Ms(5);
if(ADC_Flag)
{
ADC_Val = Get_Adc() * 3.3 / 4096.0;
Height = 100 * ADC_Val / 3.3;
if(Height <= Threshold1)
{
Level = 0;
}else
if((Height > Threshold1) && (Height <= Threshold2))
{
Level = 1;
}else
if((Height > Threshold2) && (Height <= Threshold3))
{
Level = 2;
}else
if(Height > Threshold3)
{
Level = 3;
}
ADC_Flag = 0;
}
if(RXOVER)
{
Shan3_sum = 10;
if(RX_BUF[0] == 'C')
{
for(i = 0;i < 20;i++)
{
string[i] = 0;
}
sprintf((char*)string,"C:H%d+L%d\r\n",Height,Level);
USART2_SendString(string);
}
if(RX_BUF[0] == 'S')
{
for(i = 0;i < 20;i++)
{
string[i] = 0;
}
sprintf((char*)string,"S:TL%d+TM%d+TH%d\r\n",Threshold1,Threshold2,Threshold3);
USART2_SendString(string);
}
for(i = 0;i < 20;i++)
{
RX_BUF[i] = 0;
}
USART_ITConfig(USART2,USART_IT_RXNE, ENABLE);
RXOVER = 0;
}
if(KEY_Flag)
{
KEY_Read();
KEY_Flag = 0;
}
void KEY_Read(void)
{
static u16 key1_sum,key2_sum,key3_sum,key4_sum;
// KEY1
if(KEY1 == 0)
{
key1_sum++;
if(key1_sum == 1)
{
Set_Flag ^= 1;
LCD_ClearLine(Line0);
LCD_ClearLine(Line1);
LCD_ClearLine(Line2);
LCD_ClearLine(Line3);
LCD_ClearLine(Line4);
LCD_ClearLine(Line5);
LCD_ClearLine(Line6);
LCD_ClearLine(Line7);
LCD_ClearLine(Line8);
LCD_ClearLine(Line9);
}
}else
{
key1_sum = 0;
}
// KEY2
if((KEY2 == 0) && Set_Flag)
{
key2_sum++;
if(key2_sum == 1)
{
Threshold_Flag++;
if(Threshold_Flag >= 4) Threshold_Flag = 1;
}
}else
{
key2_sum = 0;
}
// KEY3
if((KEY3 == 0) && Set_Flag)
{
key3_sum++;
if(key3_sum == 1)
{
if(Threshold_Flag == 1)
{
Threshold1 += 5;
}
if(Threshold_Flag == 2)
{
Threshold2 += 5;
}
if(Threshold_Flag == 3)
{
Threshold3 += 5;
}
if(Threshold1 > 95) Threshold1 = 95;
if(Threshold2 > 95) Threshold2 = 95;
if(Threshold3 > 95) Threshold3 = 95;
_24c02_Write(0x00,Threshold1);
Delay_Ms(5);
_24c02_Write(0x01,Threshold2);
Delay_Ms(5);
_24c02_Write(0x02,Threshold3);
Delay_Ms(5);
}
}else
{
key3_sum = 0;
}
// KEY4
if((KEY4 == 0) && Set_Flag)
{
key4_sum++;
if(key4_sum == 1)
{
if(Threshold_Flag == 1)
{
Threshold1 -= 5;
}
if(Threshold_Flag == 2)
{
Threshold2 -= 5;
}
if(Threshold_Flag == 3)
{
Threshold3 -= 5;
}
if(Threshold1 < 5) Threshold1 = 5;
if(Threshold2 < 5) Threshold2 = 5;
if(Threshold3 < 5) Threshold3 = 5;
_24c02_Write(0x00,Threshold1);
Delay_Ms(5);
_24c02_Write(0x01,Threshold2);
Delay_Ms(5);
_24c02_Write(0x02,Threshold3);
Delay_Ms(5);
}
}else
{
key4_sum = 0;
}
}
if(LED_Flag) // 100ms
{
LD1_Flag++;
if(LD1_Flag == 10)
{
LD1_Flag = 0;
LED_MODE ^= (1<<8);
}
if(Level_Last != Level)
{
Shan2_sum = 10;
if(Level > Level_Last)
{
for(i = 0;i < 20;i++)
{
string[i] = 0;
}
sprintf((char*)string,"A:H%d+L%d+U\r\n",Height,Level);
USART2_SendString(string);
}else
if(Level < Level_Last)
{
for(i = 0;i < 20;i++)
{
string[i] = 0;
}
sprintf((char*)string,"A:H%d+L%d+D\r\n",Height,Level);
USART2_SendString(string);
}
Level_Last = Level;
}
if(!(LD1_Flag % 2)) // 200ms
{
if(Shan2_sum)
{
LED_MODE ^= (1<<9);
Shan2_sum--;
}
if(Shan3_sum)
{
LED_MODE ^= (1<<10);
Shan3_sum--;
}
}
GPIOC-> ODR = LED_MODE;
GPIOD-> ODR |= (1<<2);
GPIOD-> ODR &=~(1<<2);
LED_Flag = 0;
}
if(Display_Flag)
{
if(!Set_Flag)
{
LCD_SetTextColor(White);
LCD_DisplayStringLine(Line1, (u8*)" Liquid Level ");
sprintf((char*)string," Height : %dcm ",Height);
LCD_DisplayStringLine(Line3, string);
sprintf((char*)string," ADC : %.2fV ",ADC_Val);
LCD_DisplayStringLine(Line5, string);
sprintf((char*)string," Level : %d ",Level);
LCD_DisplayStringLine(Line7, string);
}else
{
LCD_SetTextColor(White);
LCD_DisplayStringLine(Line1, (u8*)" Parameter Setup ");
if(Threshold_Flag == 1)
{
LCD_SetTextColor(Green);
}else
{
LCD_SetTextColor(White);
}
sprintf((char*)string," Threshold 1 : %dcm ",Threshold1);
LCD_DisplayStringLine(Line3, string);
if(Threshold_Flag == 2)
{
LCD_SetTextColor(Green);
}else
{
LCD_SetTextColor(White);
}
sprintf((char*)string," Threshold 2 : %dcm ",Threshold2);
LCD_DisplayStringLine(Line5, string);
if(Threshold_Flag == 3)
{
LCD_SetTextColor(Green);
}else
{
LCD_SetTextColor(White);
}
sprintf((char*)string," Threshold 3 : %dcm ",Threshold3);
LCD_DisplayStringLine(Line7, string);
}
Display_Flag = 0;
}
#include "IO.h"
extern u16 LED_MODE;
u8 Set_Flag = 0;
u8 Threshold_Flag = 1;
extern u8 Threshold1;
extern u8 Threshold2;
extern u8 Threshold3;
/////////////////////// 24c02 ///////////////////////
void _24c02_Write(u8 address,u8 data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
}
u8 _24c02_Read(u8 address)
{
u8 temp;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
temp = I2CReceiveByte();
I2CWaitAck();
I2CStop();
return temp;
}
//////////////////////// ADC ///////////////////////
void ADC1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOB, &GPIO_InitStructure);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
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);
ADC_ResetCalibration( ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
u16 Get_Adc(void)
{
u16 temp;
ADC_RegularChannelConfig( ADC1,ADC_Channel_8, 1, ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd( ADC1, ENABLE);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == 0);
temp = ADC_GetConversionValue( ADC1);
ADC_SoftwareStartConvCmd( ADC1, DISABLE);
return temp;
}
/////////////////////// USART2 ///////////////////////////
void USART2_Init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
USART_ITConfig(USART2,USART_IT_RXNE, ENABLE);
}
void USART2_SendString(u8 *str)
{
u8 index = 0;
do
{
USART_SendData(USART2, str[index]);
while(USART_GetFlagStatus( USART2,USART_FLAG_TXE) == 0);
index++;
}while(str[index] != 0);
}
//////////////////////// LED /////////////////////////
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 0XFF00;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOC, &GPIO_InitStructure);
GPIOC-> ODR = 0XFFFF;
GPIOD-> ODR |= (1<<2);
GPIOD-> ODR &=~(1<<2);
}
////////////////////// KEY //////////////////////////
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_Init( GPIOB, &GPIO_InitStructure);
}