第七届蓝桥杯嵌入式
这一届的蓝桥杯省题他的用到的外设相对于来说还是比较多的,有用到ADC、EEPROM、USART、led、key这些外设,可以说除了没用到PWM、蜂鸣器之外,蓝桥杯嵌入式的考点涉及的外设大多都包含在里面了。可以说也是比较齐全了,不过我们也不要给自己太大的压力,把基本的配置学会了,main函数编写起来难度也不是很大的。
第七届题目要求是模拟液位警报系统,要求通过模拟电压信号(ADC)计算他液位高度,并在液位等级发生变化的时候通过串口发送到PC机上。
下面我们看看具体的要求。
1.液位高度、ADC的分析
这里说明了液位的高度是由H=Vr37*K公式得出,并且当我们模拟电压为3.3时,高度为100.然后我们可以发现这个图片ADC=1.65V时,高度=50,即可推导出K约等于30.3。知道了这些参数就可以计算他的高度了。
2.液位等级的判定
3.按键的设定
这里四个按键说明:
B1:是参数界面和设定界面的切换
B2:是在设定界面上切换阈值并凸显位置(即为高亮)
B3:是在相对应的阈值中,进行阈值的加运算,按下一次+5,直至95为止
B4:是在相对应的阈值中,进行阈值的减运算,按下一次-5,直至5为止
4.串口的设置
串口要求主要为查询和输出:
查询:
当我们串口从PC机上接受到字符“C“时,串口打印当前的液位高度和液位等级。
当我们串口从PC机上接受到字符“S“时,串口打印当前三个阈值的大小参数。
输出:
当我们检测到我们液位等级发生变化(上升或下降)的时候串口打印当前的液位高度和液位等级,并告知是上升或下降。
5、led设置
led没啥好说的,赛题分析完了,还是看代码部分吧
代码
1.main
#include "stm32f10x.h"
#include "stdio.h"
#include "led.h"
#include "i2c.h"
#include "key.h"
#include "adc.h"
#include "usart.h"
#include "string.h"
#include "lcd.h"
u32 TimingDelay = 0;
u32 LD2_delay=0;
u32 LD3_delay=0;
unsigned char i=0;
u8 RXBUF[20]; //串口数组
u8 RXCUNT=0; //计数位
u8 RXOVER=0; //标志位
unsigned char key_val; //按键存储值
unsigned int adc_val; //adc存储值
unsigned char i2c_val; //i2c存储值
unsigned char chun_chu[20];
unsigned char H; //等级比较
unsigned char B1=0; //界面切换
unsigned char B2=0; //高亮切换
unsigned char level; //液位等级
float hight=30.3; //K值
unsigned char Threshold1=30; //阈值1
unsigned char Threshold2=50;
unsigned char Threshold3=70;
unsigned char LD2_l; //下降标志
unsigned char LD2_h; //上升标志
unsigned char usart_LD3; //串口发送标志
void lcd_caozuo()
{
if(B1==0) //参数界面
{
adc_val=adc_scanf(); //读取adc的值
LCD_DisplayStringLine(Line1," Liquid Level ");
if((float)adc_val*3.3/4095!=3.3)
{
sprintf((char *)chun_chu," Height:%2ucm ",(int)(((float)adc_val*3.3/4095)*hight)); //液位高度的计算公式
LCD_DisplayStringLine(Line3,chun_chu);
}
else if((float)adc_val*3.3/4095==3.3)
{
LCD_DisplayStringLine(Line3," Height:100cm ");
}
sprintf((char *)chun_chu," ADC:%4.2fV ",(float)adc_val*3.3/4095); //ADC的值
LCD_DisplayStringLine(Line5,chun_chu);
if((int)(((float)adc_val*3.3/4095)*hight)<=Threshold1) //当液位等级为0
{
level=0;
sprintf((char *)chun_chu," Level:%1u ",level);
LCD_DisplayStringLine(Line7,chun_chu);
if(H>level) //下降
{
LD2_l=1;
sprintf((char *)RXBUF,"A:H%2u+L%1u+D\r\n",(int)(((float)adc_val*3.3/4095)*hight),level); //打印液位高度、等级和变化趋势
USART_SendString(USART2,RXBUF);
}
H=0; //重新赋值
}
if(Threshold1<(int)(((float)adc_val*3.3/4095)*hight)&&(int)(((float)adc_val*3.3/4095)*hight)<=Threshold2)//等级1
{
level=1;
sprintf((char *)chun_chu," Level:%1u ",level);
LCD_DisplayStringLine(Line7,chun_chu);
if(H>level)//下降
{
LD2_l=1;
sprintf((char *)RXBUF,"A:H%2u+L%1u+D\r\n",(int)(((float)adc_val*3.3/4095)*hight),level);
USART_SendString(USART2,RXBUF);
}
if(H<level) //上升
{
LD2_h=1;
sprintf((char *)RXBUF,"A:H%2u+L%1u+U\r\n",(int)(((float)adc_val*3.3/4095)*hight),level);
USART_SendString(USART2,RXBUF);
}
H=1;
}
if(Threshold2<(int)(((float)adc_val*3.3/4095)*hight)&&(int)(((float)adc_val*3.3/4095)*hight)<=Threshold3) //等级2
{
level=2;
sprintf((char *)chun_chu," Level:%1u ",level);
LCD_DisplayStringLine(Line7,chun_chu);
if(H>level)
{
LD2_l=1; //下降
sprintf((char *)RXBUF,"A:H%2u+L%1u+D\r\n",(int)(((float)adc_val*3.3/4095)*hight),level);
USART_SendString(USART2,RXBUF);
}
if(H<level) //上升
{
LD2_h=1;
sprintf((char *)RXBUF,"A:H%2u+L%1u+U\r\n",(int)(((float)adc_val*3.3/4095)*hight),level);
USART_SendString(USART2,RXBUF);
}
H=2;
}
if((int)(((float)adc_val*3.3/4095)*hight)>Threshold3)
{
level=3;
sprintf((char *)chun_chu," Level:%1u ",level);
LCD_DisplayStringLine(Line7,chun_chu);
if(H>level)
{
LD2_l=1;
sprintf((char *)RXBUF,"A:H%2u+L%1u+D\r\n",(int)(((float)adc_val*3.3/4095)*hight),level);
USART_SendString(USART2,RXBUF);
}
if(H<level)
{
LD2_h=1;
sprintf((char *)RXBUF,"A:H%2u+L%1u+U\r\n",(int)(((float)adc_val*3.3/4095)*hight),level);
USART_SendString(USART2,RXBUF);
}
H=3;
}
}
if(B1==1) //阈值设定切面
{
LCD_DisplayStringLine(Line1," Parameter Setup ");
i2c_write(0x01,Threshold3+Threshold2+Threshold1); //eeprom保存
Delay_LCD(30);
i2c_val=i2c_read(0x01);
if(B2==0)//不高亮
{
i2c_val=Threshold1;
sprintf((char *)chun_chu," Threshold1:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line3,chun_chu);
i2c_val=Threshold2;
sprintf((char *)chun_chu," Threshold2:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line5,chun_chu);
i2c_val=Threshold3;
sprintf((char *)chun_chu," Threshold3:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line7,chun_chu);
LCD_DisplayStringLine(Line9," ");
}
if(B2==3)//第三行高亮
{
LCD_SetBackColor(Yellow);
i2c_val=Threshold1;
sprintf((char *)chun_chu," Threshold1:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line3,chun_chu);
LCD_SetBackColor(Blue);
i2c_val=Threshold2;
sprintf((char *)chun_chu," Threshold2:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line5,chun_chu);
i2c_val=Threshold3;
sprintf((char *)chun_chu," Threshold3:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line7,chun_chu);
LCD_DisplayStringLine(Line9," ");
}
if(B2==5) //第五行高亮
{
i2c_val=Threshold1;
sprintf((char *)chun_chu," Threshold1:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line3,chun_chu);
LCD_SetBackColor(Yellow);
i2c_val=Threshold2;
sprintf((char *)chun_chu," Threshold2:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line5,chun_chu);
LCD_SetBackColor(Blue);
i2c_val=Threshold3;
sprintf((char *)chun_chu," Threshold3:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line7,chun_chu);
LCD_DisplayStringLine(Line9," ");
}
if(B2==7) //第七行高亮
{
i2c_val=Threshold1;
sprintf((char *)chun_chu," Threshold1:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line3,chun_chu);
i2c_val=Threshold2;
sprintf((char *)chun_chu," Threshold2:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line5,chun_chu);
LCD_SetBackColor(Yellow);
i2c_val=Threshold3;
sprintf((char *)chun_chu," Threshold3:%2ucm ",i2c_val);
LCD_DisplayStringLine(Line7,chun_chu);
LCD_SetBackColor(Blue);
LCD_DisplayStringLine(Line9," ");
}
}
}
void key_caozuo(void)
{
key_val=key_scanf(); //读取按键值
if(key_val==1) //B1按下
{
switch(B1) //界面切换
{
case 0:B1=1;break;
case 1:B1=0;break;
}
}
if(key_val==2) //B2按下
{
if(B1==1) //在阈值界面下有效
{
switch(B2) //高亮切换
{
case 0:B2=3;break;
case 3:B2=5;break;
case 5:B2=7;break;
case 7:B2=0;break;
}
}
if(key_val==3) //B3按下
{
if(B1==1) //在阈值界面下有效
{
if(B2==3) //第三行高亮
{
if(Threshold1!=95) //+5
Threshold1=Threshold1+5;
}
if(B2==5)//第5行高亮
{
if(Threshold2!=95)
Threshold2=Threshold2+5;
}
if(B2==7)//第7行高亮
{
if(Threshold3!=95)
Threshold3=Threshold3+5;
}
}
}
if(key_val==4) //B4按下
{
if(B1==1) //在阈值界面下有效
{
if(B2==3)
{
if(Threshold1!=5)
Threshold1=Threshold1-5;
}
if(B2==5)
{
if(Threshold2!=5)
Threshold2=Threshold2-5;
}
if(B2==7)
{
if(Threshold3!=5)
Threshold3=Threshold3-5;
}
}
}
}
//Main Body
int main(void)
{
SysTick_Config(72000);
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
i2c_init();
led_init();
key_init();
adc_init();
USART2_Init(9600);
while(1)
{
lcd_caozuo();
key_caozuo();
if(RXOVER==1) //串口接收处理
{
RXOVER=0; //标志位清零
usart_LD3=0; //标志位
USART_ITConfig(USART2,USART_IT_RXNE, ENABLE);
if(RXBUF[0]=='C') //接收到“C”打印,并串口LD3=1;
{
usart_LD3=1;
sprintf((char *)RXBUF,"C:H%2u+L%1u\r\n",(int)(((float)adc_val*3.3/4095)*hight),level);
USART_SendString(USART2,RXBUF);
}
if(RXBUF[0]=='S')
{
usart_LD3=1;
sprintf((char *)RXBUF,"S:TL%2u+TM%2u+TH%2u\r\n",Threshold1,Threshold2,Threshold3);
USART_SendString(USART2,RXBUF);
}
memset(RXBUF,'\0',sizeof(RXBUF)); //清空数组
}
}
}
//
void SysTick_Handler(void)
{
led_init();
TimingDelay++;
if(TimingDelay<900)
led_scanf(0,led0);
if(TimingDelay==1000)
TimingDelay=0;
if(TimingDelay>900)
led_scanf(1,led0);
if(LD2_l==1||LD2_h==1)
{
LD2_delay++;
for(i=0;i<5;i++)
{
if(LD2_delay<100)
led_scanf(0,led1);
if(LD2_delay==200)
LD2_delay=0;
if(LD2_delay>100)
led_scanf(1,led1);
}
}
if(usart_LD3==1)
{
LD3_delay++;
for(i=0;i<5;i++)
{
if(LD3_delay<100)
led_scanf(0,led2);
if(LD3_delay==200)
LD3_delay=0;
if(LD3_delay>100)
led_scanf(1,led2);
}
}
}
2.usart
#include "usart.h"
extern u8 RXBUF[20];
extern u8 RXCUNT; //½ÓÊܼÆÊý
extern u8 RXOVER; //±ê־λ
void USART2_Init(unsigned long ulBaud)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStruct);
USART_InitStruct.USART_BaudRate = ulBaud;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStruct.USART_HardwareFlowControl= USART_HardwareFlowControl_None;//Ó²¼þ¿ØÖÆÁ÷£¬Ò»°ãÑ¡ÔñNone
USART_Init(USART2, &USART_InitStruct);
// ÔÊÐíUSART2
USART_Cmd(USART2, ENABLE);
// ÔÊÐíUSART2½ÓÊÕÖжÏ
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
// ÔÊÐíNVIC USART2ÖжÏ
NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;//ÖжÏͨµÀΪUSART2
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;//ÏÈÕ¼ÓÅÏȼ¶
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;//´ÓÓÅÏȼ¶
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//ÖжÏʹÄÜ
NVIC_Init(&NVIC_InitStruct);//³õʼ»¯
}
unsigned char USART_SendChar(USART_TypeDef* USARTx, unsigned char ucChar)
{
while(!USART_GetFlagStatus(USARTx, USART_FLAG_TXE));//²»¶Ï¼ì²é±ê־λ
USART_SendData(USARTx, ucChar);//·¢ËÍ×Ö·ûÊý¾Ý
return ucChar;//·µ»Ø·¢Ë͵Ä×Ö·û
}
void USART_SendString(USART_TypeDef* USARTx, unsigned char* pucStr)
{
while(*pucStr != '\0')
USART_SendChar(USARTx, *pucStr++);
}
void USART2_IRQHandler(void)
{
u8 temp;
if(USART_GetITStatus(USART2,USART_IT_RXNE) == SET)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
temp = USART_ReceiveData(USART2);
if(temp == '\n')
{
RXCUNT = 0;
RXOVER = 1;
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
}else
{
RXBUF[RXCUNT] = temp;
RXCUNT++;
}
}
}
3.adc
#include "adc.h"
void adc_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
ADC_InitTypeDef ADC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_ADC1,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;
ADC_InitStruct.ADC_NbrOfChannel=1;
ADC_InitStruct.ADC_ScanConvMode=DISABLE;
ADC_Init(ADC1,&ADC_InitStruct);
ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_1Cycles5);
ADC_Cmd(ADC1,ENABLE);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
unsigned int adc_scanf(void)
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));
return ADC_GetConversionValue(ADC1);
}
4.key
#include "key.h"
#include "lcd.h"
void key_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
}
unsigned char key_scanf(void)
{
unsigned char key_but=0;
if(key0==0||key1==0||key2==0||key3==0)
{
Delay_LCD(100);
if(key0==0) key_but=1;
if(key1==0) key_but=2;
if(key2==0) key_but=3;
if(key3==0) key_but=4;
}
return key_but;
}
5.led
#include "led.h"
void led_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=led0|led1|led2|led3|led4|led5|led6|led7;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOD,&GPIO_InitStruct);
GPIO_SetBits(GPIOD,GPIO_Pin_2);
GPIO_SetBits(GPIOC,ledall);
GPIO_ResetBits(GPIOD,GPIO_Pin_2);
}
void led_scanf(unsigned char mode,unsigned int led)
{
if(mode==0)//Èç¹ûstate==0
{
GPIO_SetBits(GPIOD,GPIO_Pin_2);//PD2Êä³ö¸ßµçƽ
GPIO_ResetBits(GPIOC,led);//ledÊä³öµÍµçƽ
GPIO_ResetBits(GPIOD,GPIO_Pin_2);//PDÊä³öµÍµçƽ
}
else if(mode==1)//Èç¹ûstate==1
{
GPIO_SetBits(GPIOD,GPIO_Pin_2);//PD2Êä³ö¸ßµçƽ
GPIO_SetBits(GPIOC,led);//ledÊä³ö¸ßµçƽ
GPIO_ResetBits(GPIOD,GPIO_Pin_2);//PDÊä³öµÍµçƽ
}
}
- i 2c 这个我就放读和写的程序吧,官方也会给i2c的程序,就只要编写读写就行了。
unsigned char i2c_read(unsigned char add)
{
unsigned char data;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(add);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
data=I2CReceiveByte();
I2CSendAck();
I2CStop();
return data;
}
// AT24C02д
//Èë¿Ú²ÎÊý£ºaddÊǵØÖ·£¬±ÈÈç0x01,0x02µÈµÈ£»dataÊÇдÈëµÄÊý¾Ý£¬ÊÇunsigned charÐÍ
void i2c_write(unsigned char add,unsigned char data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(add);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();
}
注意:
在串口接收的时候必须要加一个 memset(RXBUF,’\0’,sizeof(RXBUF));进行对数组的清空操作。另外这个memset函数必须要加上头文件#include "string.h"才有用。
参加这种动手能力的比赛,大家还是多动手,多去理解才是王道,这样理解更加的深刻。
祝大家都能得奖。