/*赛题:第七届:模拟液位检测告警系统”
**作者:*wj
**时间:2021-2-13
**注意:设备通过串口发送给PC,思路和LCD动态显示一样(记得添加"stdio.h")
*/
**第一部分:逻辑功能实现**
#include "stm32f10x.h"
#include "lcd.h"
#include "led.h"
#include "key.h"
#include "i2c.h"
#include "stdio.h"
#include "usart.h"
#include "adc.h"
u32 TimingDelay = 0;
u8 text1[20]; //字符串数组1
u8 text2[20]; //字符串数组2
u8 RXBUF[20]; //串口接收数组
u8 TXBUF[20]; //串口发送数组
u8 RXOVER = 0; //串口接收标志0:没有接收 1:接收
u8 RXCOUNT = 0; //串口数组计数变量
u8 ADC_Flag =1; //ADC以1s间隔采集变量 1:采集(初始化为1,是让上电之后就进行一次电压采集)
u8 K1_FLAG = 0; //B1 按键: “设置”按键 0:液位检测界面 1://阈值设置界面
u8 K2_FLAG = 0; //B2 按键:切换选择 3 个待修改的阈值,被选中的阈值应突出显示
u8 LED1_on = 0; //控制LED1开变量
u8 LED1_off = 0; //控制LED1关变量
u8 Threshold_1 = 30; //液位范围1
u8 Threshold_2 = 50; //液位范围2
u8 Threshold_3 = 70; //液位范围3
u8 Level_old = 0; //上一次的水平值
u8 Level_now= 0; //新的水平值
u8 Height = 0; //液面高度变量
float ADC_Value; //ADC采集的值(浮点型)
u8 i = 0; //循环变量
u8 j = 0; //循环变量
u8 k = 0; //循环变量
/************************函数引用**************************************/
void Delay_Ms(u32 nTime);
void RCC_Configuration(void);
void LCD_Init(void);
void KEY_Scan(void);
void _24c02_Write(u16 addr, u16 data);
u16 _24c02_Read(u16 addr);
void LCD_Display(void);
void Deal_Data(void);
void LED_Blink(void);
/************************Main Body函数**************************************/
int main(void)
{
i2c_init(); //IIC初始化
LCD_Init(); //LCD初始化
RCC_Configuration(); //所有外设时钟配置
LED_Configuration(); //LED配置
KEY_Configuration(); //KEY配置
USART2_Configuration(); //串口通信2配置
ADC_Configuration(); //ADC配置
while(1)
{
KEY_Scan(); //按键扫描函数
Deal_Data(); //数据处理比较函数
LCD_Display(); //LCD显示函数
LED_Blink(); //LED闪烁配置函数
}
}
/************************LCD_Init初始化函数**************************************/
void LCD_Init(void)
{
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
SysTick_Config(SystemCoreClock/1000);
//第一次给EEPROM写入数据
// _24c02_Write(0x01,30);
// Delay_Ms(10);
// _24c02_Write(0x02,50);
// Delay_Ms(10);
// _24c02_Write(0x03,70);
// Delay_Ms(10);
//上电之后读取之前存储的数据
Threshold_1 = _24c02_Read(0x01);
Delay_Ms(10);
Threshold_2 = _24c02_Read(0x02);
Delay_Ms(10);
Threshold_3 = _24c02_Read(0x03);
}
/************************LCD_Display显示函数**************************************/
void LCD_Display(void)
{
if(K1_FLAG == 0) // 液位检测界面
{
LCD_DisplayStringLine(Line2 ," Liquid Level ");
sprintf((char*)text1," Height: %dcm ",Height);
LCD_DisplayStringLine(Line4,text1);
if(ADC_Flag == 1)
{
ADC_Flag =0;
ADC_Value = Get_ADC(8) * 3.3 /0xfff;
sprintf((char*)text2," ADC_VAL: %.2fV ",ADC_Value); //保留俩位小数:.2f
LCD_DisplayStringLine(Line6,text2);
}
sprintf((char*)text1," Level: %d ",Level_now);
LCD_DisplayStringLine(Line8,text1);
_24c02_Write(0x01,Threshold_1);
Delay_Ms(10);
_24c02_Write(0x02,Threshold_2);
Delay_Ms(10);
_24c02_Write(0x03,Threshold_3);
Delay_Ms(10);
}
else if(K1_FLAG == 1) //阈值设置界面
{
LCD_SetBackColor(Blue); //第一行一直显示蓝色
LCD_DisplayStringLine(Line2 ," Parameter Setup ");
if(K2_FLAG == 1)
{
LCD_SetBackColor(Red); //选中高亮显示
sprintf((char*)text1," Threshold 1: %dcm ",Threshold_1);
LCD_DisplayStringLine(Line4,text1);
}
else
{
LCD_SetBackColor(Blue);
sprintf((char*)text1," Threshold 1: %dcm ",Threshold_1);
LCD_DisplayStringLine(Line4,text1);
}
if(K2_FLAG == 2)
{
LCD_SetBackColor(Red);
sprintf((char*)text1," Threshold 2: %dcm ",Threshold_2);
LCD_DisplayStringLine(Line5,text1);
}
else
{
LCD_SetBackColor(Blue);
sprintf((char*)text1," Threshold 2: %dcm ",Threshold_2);
LCD_DisplayStringLine(Line5,text1);
}
if(K2_FLAG == 3)
{
LCD_SetBackColor(Red);
sprintf((char*)text1," Threshold 3: %dcm ",Threshold_3);
LCD_DisplayStringLine(Line6,text1);
}
else
{
LCD_SetBackColor(Blue);
sprintf((char*)text1," Threshold 3: %dcm ",Threshold_3);
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200225154220972.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDIzNjMwMg==,size_16,color_FFFFFF,t_70)LCD_DisplayStringLine(Line6,text1);
}
//设置不要的行的颜色为背景颜色
LCD_SetBackColor(Blue);
LCD_DisplayStringLine(Line0 ," ");
LCD_DisplayStringLine(Line1 ," ");
LCD_DisplayStringLine(Line3 ," ");
LCD_DisplayStringLine(Line7 ," ");
LCD_DisplayStringLine(Line8 ," ");
LCD_DisplayStringLine(Line9 ," ");
}
//串口部分
if(RXOVER)
{
RXOVER = 0;
if(RXBUF[0] == 'C')
{
sprintf((char*)TXBUF,"C:H%d+L%d\r\n",Height,Level_now);
Send_String(TXBUF);
}
else if(RXBUF[0] == 'S')
{
sprintf((char*)TXBUF,"S:TL%d+TM%d+TH%d\r\n",Threshold_1,Threshold_2,Threshold_3);
Send_String(TXBUF);
}
for(k=0;k<5;k++)
{
LED_Control(LED1,1);
LED_Control(LED3,0);
Delay_Ms(200);
LED_Control(LED3,1);
Delay_Ms(200);
}
for(i=0;i<20;i++)
{
RXBUF[i] = 0;
}
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
}
/************************液位水平比较函数**************************************/
void Deal_Data(void)
{
Height = ADC_Value * 100 / 3.3; //根据题目要求的关系
if(Height <= Threshold_1)
{
Level_now = 0;
}
else if((Threshold_1 < Height ) && (Height <= Threshold_2))
{
Level_now = 1;
}
else if((Threshold_2 < Height ) && (Height <= Threshold_3))
{
Level_now = 2;
}
else if(Threshold_3 < Height )
{
Level_now = 3;
}
}
/************************LED闪烁函数**************************************/
void LED_Blink(void)
{
//LED1_配置
if(K1_FLAG == 0) //运行状态下
{
if(LED1_on == 1)
{
LED1_on =0;
LED_Control(LED1,0);
}
if(LED1_off == 1)
{
LED1_off=0;
LED_Control(LED1,1);
}
}
else
{
LED_Control(LED1,1);
}
//LED2_配置
if(Level_old != Level_now)
{
if(Level_now > Level_old)
{
sprintf((char*)TXBUF,"A:H%d+L%d+U\r\n",Height,Level_now);
Send_String(TXBUF);
}
if(Level_now < Level_old)
{
sprintf((char*)TXBUF,"A:H%d+L%d+D\r\n",Height,Level_now);
Send_String(TXBUF);
}
for(j=0;j<5;j++)
{
LED_Control(LED1,1);
LED_Control(LED2,0);
Delay_Ms(200);
LED_Control(LED2,1);
Delay_Ms(200);
}
}
Level_old = Level_now; //加载上一次的液位等级
}
/************************外设时钟函数**************************************/
void RCC_Configuration(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD , ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
}
/************************外设时钟函数**************************************/
void KEY_Scan(void)
{
if(K1 == 0)
{
Delay_Ms(10);
if(K1 == 0)
{
if(K1_FLAG == 0)
{
K1_FLAG = 1;
}
else
{
K1_FLAG = 0;
}
}
while(K1 == 0)
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);
}
if(K2 == 0 && K1_FLAG == 1)
{
Delay_Ms(10);
if(K2 == 0 && K1_FLAG == 1)
{
if(K2_FLAG < 3)
K2_FLAG++;
else
K2_FLAG=1;
}
while(K2 == 0);
}
if(K3 == 0)
{
Delay_Ms(10);
if(K3 == 0)
{
if(K2_FLAG == 1)
{
if(Threshold_1 < Threshold_2)
Threshold_1 +=5;
else
Threshold_1 = Threshold_2;
}
else if(K2_FLAG == 2)
{
if(Threshold_2<Threshold_3)
Threshold_2 +=5;
else
Threshold_2 = Threshold_3;
}
else if(K2_FLAG == 3)
{
if(Threshold_3<90)
Threshold_3 +=5;
else
Threshold_3 = 95;
}
}
while(K3 == 0);
}
if(K4 == 0)
{
Delay_Ms(10);
if(K4 == 0)
{
if(K2_FLAG == 1)
{
if(Threshold_1>5)
Threshold_1 -=5;
else
Threshold_1 = 5;
}
else if(K2_FLAG == 2)
{
if(Threshold_2 >Threshold_1)
Threshold_2 -=5;
else
Threshold_2 = Threshold_1;
}
else if(K2_FLAG == 3)
{
if(Threshold_3>Threshold_2)
Threshold_3 -=5;
else
Threshold_3 = Threshold_2;
}
}
while(K4 == 0);
}
}
void _24c02_Write(u16 addr, u16 data)
{
I2CStart();
I2CSendByte(0xa0);
I2CSendAck();
I2CSendByte(addr);
I2CSendAck();
I2CSendByte(data);
I2CSendAck();
I2CStop();
}
u16 _24c02_Read(u16 addr)
{
u16 temp;
I2CStart();
I2CSendByte(0xa0);
I2CSendAck();
I2CSendByte(addr);
I2CSendAck();
I2CStart();
I2CSendByte(0xa1);
I2CSendAck();
temp = I2CReceiveByte();
I2CSendAck();
I2CStop();
return temp;
}
void Delay_Ms(u32 nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
第二部分:初始化配置
#define LED1 GPIO_Pin_8
#define LED2 GPIO_Pin_9
#define LED3 GPIO_Pin_10
#define LED4 GPIO_Pin_11
#define LED5 GPIO_Pin_12
#define LED6 GPIO_Pin_13
#define LED7 GPIO_Pin_14
#define LED8 GPIO_Pin_15
#define LEDALL GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15
#include "led.h"
/**
功能:初始化LED管脚
注意:为了防止LCD LED显示的冲突对LCD写函数进行了寄存器的操作
**/
void LED_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = LEDALL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
GPIO_SetBits(GPIOC,LEDALL);
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
}
/**
功能:控制LED亮灭
入口参数ledx:LED1-LED8
入口参数led_sta:低电平点亮(根据原理图配置)
**/
void LED_Control(u16 ledx,u16 led_sta)
{
if(led_sta == 0)
{
GPIO_SetBits(GPIOD,GPIO_Pin_2);
GPIO_ResetBits(GPIOC,ledx);
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
}
else
{
GPIO_SetBits(GPIOD,GPIO_Pin_2);
GPIO_SetBits(GPIOC,ledx);
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
}
}
#define K1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define K2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)
#define K3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define K4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)
#include "key.h"
void KEY_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure TIM1_CH1 (PA8) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
#include "usart.h"
void USART2_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
/* Enable the USART2 */
USART_Cmd(USART2, ENABLE);
}
/**
功能:发送字符串
入口参数:发送内容
**/
void Send_String(u8 *str)
{
u8 index = 0;
do
{
USART_SendData(USART2, str[index]);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
index++;
}
while(str[index] != 0);
}
#include "adc.h"
void ADC_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ADC时钟分频,不能超过14M,所以72/6=12M
/* ADC1 configuration ------------------------------------------------------*/
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);
/* Enable ADC1 reset calibration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
}
/**
功能:获取模拟输入变量
入口参数:ADC的通道(因为板上配置ADC_Channel_8)
局部变量:u16 temp保存读取的模拟量
返回值:temp保存读取的模拟量
**/
u16 Get_ADC(u8 channel)
{
u16 temp;
/* ADC1 regular channel14 configuration */
ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == 0); //转换结束标志ADC_FLAG_EOC
temp = ADC_GetConversionValue(ADC1);
ADC_SoftwareStartConvCmd(ADC1,DISABLE);
return temp;
}
第三部分:中断处理
extern u32 TimingDelay;
extern u8 RXBUF[20];
extern u8 RXOVER;
extern u8 RXCOUNT;
extern u8 LED1_on;
extern u8 LED1_off;
extern u8 ADC_Flag;
void SysTick_Handler(void)
{
static u16 count1 = 0 ,count2 =0;
TimingDelay--;
if(++count1 == 1000)
{
count1 = 0;
LED1_on = 1;
ADC_Flag = 1;
}
if(++count2 == 2000)
{
count2 = 0;
LED1_off = 1;
}
}
void USART2_IRQHandler(void)
{
u8 temp;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
temp = USART_ReceiveData(USART2);
if(temp == '\n' || RXCOUNT ==20)
{
// RXBUF[RXCOUNT - 1] = 0; //防止最后出现乱码\r
RXOVER = 1;
RXCOUNT=0;
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
}
else
{
RXBUF[RXCOUNT] = temp;
RXCOUNT++;
}
}
}