蓝桥杯嵌入式开发经验分享(第七届嵌入式模拟——“电压测量监控设备”)

作者:马一飞                                                         QQ:791729359       

在学习过程中有什么问题可以联系

(本篇博客有很多还没讲解很细致,先贴出代码,等有时间再进行注解)

一、题目

        设计一个电压测量监控设备,定时通过串口向 PC 机发送电压值,通过串口接收系统配置参数并保存到 E2PROM 中。设备硬件部分主要由电源部分、控制器单元、串口部分、存储单元组成,系统框图如图 1 所示  :

                                 蓝桥杯嵌入式开发经验分享(第七届嵌入式模拟——“电压测量监控设备”)_第1张图片

设计任务及要求

1. RTC 实时时钟

        使用 STM32 内部 RTC 完成相关功能,设备上电后,时间初始化为 23 时 59 分 55 秒,默认定时上报电压时间为 0 时 0 点 0 分。

2. ADC 测量功能
        设备采集电位器 R37 输出的电压信号 V1,并通过 LCD 显示。当 V1>VDD*k 时,指示灯LD1 以 0.2 秒为间隔闪烁,闪烁功能可以通过按键关闭;VDD为 3.3V;k 默认值为 0.1,保存在 E2PROM 中并可以通过串口修改配置。

3. 串行功能
       3.1 设定 k 值,可设置范围 0.1 ~ 0.9
                格式:【命令类型】【数值】【命令结束标志】
                举例:
                “k0.1\n”
                设置 k 值为 0.1;
                设备接收到命令执行后,回复“ok\n”。
        3.2 定时上报电压 V1
                格式:【V1 电压值】+【k 值】+【时间】【命令结束标志】
                举例:
                “2.21+0.1+123030\n”
                12 时 30 分 30 秒上报电压值为 2.21V,k 值为 0.1
        说明:串口设定 9600 波特,数据位 8,停止位 1,无校验位;没有发送或发送错误
        的控制命令时,设备不做回应。

4. LCD 显示
        设备上电默认通过 LCD 显示电位器输出电压 V1(保留小数点后两位有效数字)、k 值、指示灯闪烁报警功能状态和系统时间,显示界面如图 1 所示:

                                                                    蓝桥杯嵌入式开发经验分享(第七届嵌入式模拟——“电压测量监控设备”)_第2张图片

5. 按键功能
        “B1”按键设定为“功能”按键,打开/关闭指示灯闪烁报警功能,默认为打开状态;
        “B2”按键设定为“设置”按键,设置设备自动上报电压时间,按下 B2 后,LCD 显示界面如图 2 所示,此时通过按键 B3 切换选择时、分、秒,通过按键 B4 进行调整,完成调整后,按下 B2 按键,更新自动上报时间,并返回图 1 所示的 LCD 显示界面。

                                                                     蓝桥杯嵌入式开发经验分享(第七届嵌入式模拟——“电压测量监控设备”)_第3张图片

二、模块化代码分析

1、初始化部分

#include "stm32f10x.h"
#include "lcd.h"
#include "IO.h"
#include "stdio.h"
#include "i2c.h"
u32 TimingDelay = 0;
u8 string[20];
u8 RXCUNT = 0;
u8 RXOVER = 0;
u8 RXBUF[20] = {0};
u8 RTC_flag = 0;
u32 TimeVal;
u8 key_read_flag = 0;
u8 _200ms_flag = 0;
float ADC_val;
float k;
u8 i;
extern u16 LED_MODE;
extern u8 B1_ALA_Flag;
extern u8 B2_Set_Flag;
extern u8 ALA_hour,ALA_min,ALA_sec;
void Delay_Ms(u32 nTime);
u8 hour,min,sec;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
SysTick_Config(SystemCoreClock/1000);
i2c_init();
USART2_Init(9600);
RTC_Init(23,59,55);
ADC1_Init();
LED_Init();
KEY_Init();
k = _24c02_Read(0xaa) / 10.0;

2、串口处理部分

if(RXOVER == 1)  
{
	RXOVER = 0;
	if(((RXBUF[3] - 0x30) >= 1) && ((RXBUF[3] - 0x30) <= 9))
	{
		k = (RXBUF[3] - 0x30) / 10.0;
		_24c02_Write(0xaa,RXBUF[3] - 0x30);
		USART2_SendString((u8*)"OK\n");
	}
	for(i=0;i<20;i++)
	{
		RXBUF[i] = 0;
	}
	USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
}

3、RTC部分

if(RTC_flag == 1)  //RTC
{
	RTC_flag = 0;
	TimeVal = RTC_GetCounter();
	hour = TimeVal / 3600;
	min = TimeVal % 3600 / 60;
	sec = TimeVal % 3600 % 60;
	if(TimeVal == (ALA_hour * 3600 + ALA_min * 60 + ALA_sec))
	{
		for(i=0;i<20;i++)
		{
		    string[i] = 0;
	    }
	    sprintf((char*)string,"%.2f+%.1f+%.2d%.2d%.2d\n",ADC_val,k,ALA_hour,ALA_min,ALA_sec);
		USART2_SendString(string);
	}
}

4、按键部分

if(key_read_flag == 1)  // KEY
{
	KEY_Read();
	key_read_flag = 0;
}
void KEY_Read(void)
{
	static u16 key1_sum = 0,key2_sum = 0,key3_sum = 0,key4_sum = 0;
	if(KEY1 == 0)
	{
		key1_sum++;
		if(key1_sum == 1)
		{
			B1_ALA_Flag ^= 1;
		}
	}else
	{
		key1_sum = 0;
	}
		
	if(KEY2 == 0)
	{
		key2_sum++;
		if(key2_sum == 1)
	    {
			B2_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
	{
		key2_sum = 0;
	}
		
	if(KEY3 == 0)
	{
		key3_sum++;
		if((key3_sum == 1) && B2_Set_Flag)
		{
			B3_Select_Flag++;
			if(B3_Select_Flag > 2)
			{
				B3_Select_Flag = 0;
			}
	    }
	}else
	{
		key3_sum = 0;
	}
		
	if(KEY4 == 0)
	{
		key4_sum++;
		if((key4_sum == 1) && B2_Set_Flag)
		{
			if(B3_Select_Flag == 0)
			{
				ALA_hour++;
				if(ALA_hour >= 24) ALA_hour = 0;
			}else
			if(B3_Select_Flag == 1)
			{
				ALA_min++;
				if(ALA_min >= 60) ALA_min = 0;
			}else
			if(B3_Select_Flag == 2)
			{
				ALA_sec++;
				if(ALA_sec >= 60) ALA_sec = 0;
			}
		}
	}else
	{
		key4_sum = 0;
	}
}

5、LCD显示部分

if(!B2_Set_Flag)
{
	sprintf((char*)string,"  V1 : %.2f          ",ADC_val);
	LCD_DisplayStringLine(Line3, string);
	sprintf((char*)string,"  k : %.1f          ",k);
	LCD_DisplayStringLine(Line4, string);
	if(B1_ALA_Flag)
	{
		LCD_DisplayStringLine(Line5,(u8*)"  LED : ON            ");
	}else
	{
		LCD_DisplayStringLine(Line5,(u8*)"  LED : OFF           ");
	}
	sprintf((char*)string,"  T : %.2d-%.2d-%.2d       ",hour,min,sec);
	LCD_DisplayStringLine(Line6, string);
	sprintf((char*)string,"                   %d",1);
	LCD_DisplayStringLine(Line9, string);
}else
{
	LCD_DisplayStringLine(Line3,(u8*)"     setting         ");
	sprintf((char*)string,"     %.2d-%.2d-%.2d         ",ALA_hour,ALA_min,ALA_sec);
	LCD_DisplayStringLine(Line6, string);
	sprintf((char*)string,"                   %d",2);
	LCD_DisplayStringLine(Line9, string);
}

6、ADC部分

ADC_val = Get_Adc() * 3.3 / 4096;

7、LED部分

if((ADC_val > (3.3 * k)) && (B1_ALA_Flag) && (_200ms_flag))  // LED  alarm
{
	_200ms_flag = 0;
	LED_MODE ^= (1<<8);
	GPIOC->ODR  = LED_MODE;
	GPIOD->ODR |= (1<<2);
	GPIOD->ODR &=~(1<<2);
}else
{
	LED_MODE |= (1<<8);
	GPIOC->ODR  = LED_MODE;
	GPIOD->ODR |= (1<<2);
	GPIOD->ODR &=~(1<<2);
}

8、滴答定时器及中断部分

void USART2_IRQHandler(void)
{
	u8 temp = 0;
	if(USART_GetITStatus(USART2, USART_IT_RXNE) == 1)
	{
		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++;
		}
	}
}

void RTC_IRQHandler(void)
{
	u32 counter;
	if(RTC_GetITStatus(RTC_IT_SEC) == 1)
	{
		RTC_ClearITPendingBit(RTC_IT_SEC);
		RTC_flag = 1;
		RTC_WaitForLastTask();
		counter = RTC_GetCounter();
		RTC_WaitForLastTask();
		if(counter == (23 * 3600 + 59 * 60 + 59))
		{
			RTC_SetCounter(0x0);
			RTC_WaitForLastTask();
		}
				
	}
}
void SysTick_Handler(void)
{
	static u8 key_sum = 0;
	static u8 _200ms_sum = 0;
	TimingDelay--;
	if(++key_sum == 50)  //50ms
	{
		key_sum = 0;
		key_read_flag = 1;
	}
	
	if(++_200ms_sum == 200) // 200ms
	{
		_200ms_sum = 0;
		_200ms_flag = 1;
	}
}

三、通用初始化部分

#include "IO.h"
u16 LED_MODE = 0XFFFF;
u8 B1_ALA_Flag = 1; 
u8 B2_Set_Flag = 0; 
u8 ALA_hour = 0,ALA_min = 0,ALA_sec = 0;
u8 B3_Select_Flag = 0;

void USART2_Init(u32 bound)
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_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);

	USART_InitStructure.USART_BaudRate = bound;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init(USART2, &USART_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_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);
}

void RTC_Init(u8 HH,u8 MM,u8 SS)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR,ENABLE);
	
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	PWR_BackupAccessCmd(ENABLE);
	BKP_DeInit();

	RCC_LSICmd(ENABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0);

	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
	RCC_RTCCLKCmd(ENABLE);
	
	RTC_WaitForSynchro();
	RTC_WaitForLastTask();

	RTC_ITConfig(RTC_IT_SEC,ENABLE);
	RTC_WaitForLastTask();

	RTC_SetPrescaler(40000 - 1);
	RTC_WaitForLastTask();

	RTC_SetCounter(HH * 3600 + MM * 60 + SS);
	RTC_WaitForLastTask();
}


void ADC1_Init(void)
{
	ADC_InitTypeDef ADC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_ADC1, ENABLE);
	
	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);

	RCC_ADCCLKConfig(RCC_PCLK2_Div6);

	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)
{
	ADC_RegularChannelConfig( ADC1, ADC_Channel_8, 1, ADC_SampleTime_239Cycles5);

	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	while(ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC) == 0);
		
	return ADC_GetConversionValue(ADC1);
}

void _24c02_Write(u8 address,u8 dat)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(address);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

u8 _24c02_Read(u8 address)
{
	u8 dat;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(address);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	dat = I2CReceiveByte();
	I2CWaitAck();
	I2CStop();
	return dat;
}

void LED_Init(void)
{
	GPIO_InitTypeDef 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);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	GPIOC->ODR  = LED_MODE;
	GPIOD->ODR |= (1<<2);
	GPIOD->ODR &=~(1<<2);
}


void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;	
	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);
}

 

你可能感兴趣的:(蓝桥杯)