蓝桥杯嵌入式开发经验分享(第七届国赛模拟——“电压测量与异相方波信号输出”)

作者:马一飞                                                         QQ:791729359       

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

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

一、题目

        设计一个电压测量与方波信号输出设备,设备能检测模拟信号输入,并根据检测到的电压值,计算出两路异相方波信号的相位差,输出信号频率可通过按键调整,设备硬件部分主要由电源部分、控制器单元、按键部分、存储单元和显示部分组成,系统框图如图 1 所示:

                     蓝桥杯嵌入式开发经验分享(第七届国赛模拟——“电压测量与异相方波信号输出”)_第1张图片     

        CT117E 考试板电路原理图、I2C 总线驱动程序、LCD 驱动程序及本题涉及到的芯片资料可参考计算机上的电子文档。电路原理图、程序流程图及相关工程文件请以考生准考证命名,并保存在指定文件夹中(文件夹名为考生准考证号,文件夹位于 Windows 桌面上)。

设计任务及要求

1. ADC 测量

        使用 STM32 处理器片内 ADC 采集电位器 R37 输出电压,记为 Vo,并通过 LCD 显示电压值,保留小数点后两位有效数字。

2. 异相方波输出

        使用 STM32 处理器 TIM3 通道(PA6、PA7)输出异相方波信号,PA7 输出信号相对于PA6 滞后相位差(D)与电位器输出电压之间的关系为 D = (Vo/3.3)*360°,通过按键控制信号启动、停止及调节信号输出频率。

3. 按键设置

        “B1”按键设定为“启动/停止”按键,切换信号输出状态:“启动”状态下,根据ADC采集到的电压值输出异相方波信号,指示灯 LD1点亮,“停止”状态下,两路输出通道 PA6、PA7 持续输出低电平,指示灯 LD1 熄灭。LCD 实时显示采集电压、信号输出状态和信号参数,显示界面如图 2 所示

                                                                  蓝桥杯嵌入式开发经验分享(第七届国赛模拟——“电压测量与异相方波信号输出”)_第2张图片

        “B2”按键设定为“设置”按键,按下后,进入设置界面如图3所示,此时通过“B3”和“B4”按键调整输出信号频率,可调范围为 1KHz~10KHz,每次按下“B3”按键,频率增加 1KHz,按下“B4”按键,频率减小 1KHz,调整完成后,再次按下“B2”按键,保存
信号输出频率参数到 E2PROM,并退出设置界面返回图 2 所示界面。

说明:“B3”和“B4”按键仅在设置界面下有效;设备默认输出信号频率 1KHz。               

                                                                  蓝桥杯嵌入式开发经验分享(第七届国赛模拟——“电压测量与异相方波信号输出”)_第3张图片

4. EEPROM 存储

       用于存储配置的输出信号频率参数,设备重启后,能够恢复最近一次的配置。

需要完成的要求:

1. 电压测量功能实现;
2. E2PROM 配置存储功能实现;
3. LED 指示功能实现;
4. LCD 显示与界面切换功能实现;
5. 按键切换与控制功能实现;
6. 异相方波信号输出与频率调整功能实现。

二、模块化代码分析

1、初始化部分

u32 TimingDelay = 0;
u8 string[20];
float ADC_Val;
u8 KEY_Flag = 0;
u8 ADC_Flag = 0;
u8 Display_Flag = 0;
u8 LED_Flag = 0;
u16 Deg;
u16 Deg_Last;
extern u8 Set_Flag;
extern u16 LED_MODE;
extern u8 ENABLE_Flag;
extern u16 Frequency;
void Delay_Ms(u32 nTime);
STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
	
SysTick_Config(SystemCoreClock/1000);
i2c_init();
ADC1_Init();
Frequency = _24c02_Read(0x88) * 1000;
TIM3_Output_Init(Frequency,Deg,1,ENABLE_Flag);
LED_Init();
KEY_Init();

2、按键部分

if(KEY_Flag)
{
	KEY_Flag = 0;
	KEY_Read();
}
void KEY_Read(void)
{
	static u16 key1_sum = 0,key2_sum = 0,key3_sum = 0,key4_sum = 0;
	//KEY1
	if(KEY1 == 0)
	{
		key1_sum++;
		if(key1_sum == 1)
		{
			ENABLE_Flag ^= 1;
			TIM3_Output_Init(Frequency,Deg,0,ENABLE_Flag);
		}
	}else
	{
		key1_sum = 0;
	}
		
	//KEY2
	if(KEY2 == 0)
	{
		key2_sum++;
		if(key2_sum == 1)
		{
			Set_Flag ^= 1;
			LCD_ClearLine(Line0);
			LCD_ClearLine(Line2);
			LCD_ClearLine(Line3);
			LCD_ClearLine(Line4);
			LCD_ClearLine(Line5);
			LCD_ClearLine(Line6);
			LCD_ClearLine(Line7);
			LCD_ClearLine(Line8);
			LCD_ClearLine(Line9);
			LCD_ClearLine(Line1);
			if(!Set_Flag)
			{
				_24c02_Write(0x88,Frequency / 1000);
			}
		}
	}else
	{
		key2_sum = 0;
	}
		
	//KEY3
	if((KEY3 == 0) && Set_Flag)
	{
		key3_sum++;
		if(key3_sum == 1)
		{
			Frequency += 1000;
			if(Frequency > 10000) Frequency = 10000;
			TIM3_Output_Init(Frequency,Deg,0,ENABLE_Flag);
		}
	}else
	{
		key3_sum = 0;
	}
		
	//KEY4
	if((KEY4 == 0) && Set_Flag)
	{
		key4_sum++;
		if(key4_sum == 1)
		{
			Frequency -= 1000;
			if(Frequency < 1000) Frequency = 1000;
			TIM3_Output_Init(Frequency,Deg,0,ENABLE_Flag);
		}
	}else
	{
		key4_sum = 0;
	}
}

3、ADC部分

if(ADC_Flag)
{
	ADC_Flag = 0;
	ADC_Val = Get_Adc(8) * 3.3 / 4096;
	Deg = (ADC_Val / 3.3) * 360.0;
	TIM3_Output_Init(Frequency,Deg,0,ENABLE_Flag);
}

4、LCD显示部分

if(Display_Flag)
{
	Display_Flag = 0;
	if(!Set_Flag)
	{
		sprintf((char*)string,"ADC:%.2f              ",ADC_Val);
		LCD_DisplayStringLine( Line1, string);
		if(ENABLE_Flag)
		{
			LCD_DisplayStringLine( Line3, (u8*)"Output: ON");
		}else
		{
			LCD_DisplayStringLine( Line3, (u8*)"Output:OFF");
		}
		sprintf((char*)string,"Phase:%d(deg)              ",Deg);
		LCD_DisplayStringLine( Line5, string);
		sprintf((char*)string,"Frequency:%dKHZ              ",Frequency / 1000);
		LCD_DisplayStringLine( Line7, string);
	}else
	{
		LCD_DisplayStringLine( Line3, (u8*)"     Setting       ");
		sprintf((char*)string,"  Frequency:%dKHZ        ",Frequency / 1000);
		LCD_DisplayStringLine( Line7, string);
	}
}

5、LED显示

if(LED_Flag)
{
	LED_Flag = 0;
	if(ENABLE_Flag)
	{
		LED_MODE &=~(1<<8);
	}else
	{
		LED_MODE |= (1<<8);
	}
	GPIOC->ODR = LED_MODE;
	GPIOD->ODR |= (1<<2);
	GPIOD->ODR &=~(1<<2);
}

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

extern u16 CH_Val;
extern u8 KEY_Flag;
extern u8 Display_Flag;
extern u8 ADC_Flag;
extern u8 LED_Flag;
void SysTick_Handler(void)
{
	static u8 key_sum = 0;
	static u16 adc_sum = 0;
	static u8 display_sum = 0;
	static u8 led_sum = 0;
	TimingDelay--;
	if(++led_sum == 100)
	{
		led_sum = 0;
		LED_Flag = 1;
	}
	if(++key_sum == 50) // 50ms
	{
		key_sum = 0;
		KEY_Flag = 1;
	}
	if(++adc_sum == 1000)
	{
		adc_sum = 0;
		ADC_Flag = 1;
	}
	if(++display_sum == 200)
	{
		display_sum = 0;
		Display_Flag = 1;
	}
}

void TIM3_IRQHandler(void)
{
	u16 capture;
	if(TIM_GetITStatus(TIM3, TIM_IT_CC1) == 1)
	{
		TIM_ClearITPendingBit( TIM3, TIM_IT_CC1);
		capture = TIM_GetCapture1(TIM3);
		TIM_SetCompare1(TIM3, capture + CH_Val * 0.5);
	}
		
	if(TIM_GetITStatus(TIM3, TIM_IT_CC2) == 1)
	{
		TIM_ClearITPendingBit( TIM3, TIM_IT_CC2);
		capture = TIM_GetCapture2(TIM3);
		TIM_SetCompare2(TIM3, capture + CH_Val * 0.5);
	}
}

三、通用初始化部分

#include "IO.h"
u16 CH_Val;
u16 LED_MODE = 0xffff;
u8 ENABLE_Flag = 1;
u16 Frequency = 3000;
u8 Set_Flag = 0;
extern u16 Deg;
///////////////////////   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_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	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(u8 Channel)
{
	u16 temp;
	ADC_RegularChannelConfig( ADC1,Channel, 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;
}

///////////////////////   PWM_Output   ///////////////////////
void TIM3_Output_Init(u16 fre,u16 deg,u8 status,u8 enable)
{
	u16 phase;
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	if(status)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 ,ENABLE);
	
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_Init(GPIOA, &GPIO_InitStructure);
			
		NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);
			
		TIM_TimeBaseInitStructure.TIM_Period = 0xffff;
		TIM_TimeBaseInitStructure.TIM_Prescaler = 71;
		TIM_TimeBaseInitStructure.TIM_CounterMode = 0x0;
		TIM_TimeBaseInitStructure.TIM_ClockDivision = 0x0;
		TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	}
	CH_Val = 1000000 / fre;
	phase = CH_Val * deg / 360;
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
	if(enable)
	{
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	}else
	{
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
	}
	TIM_OCInitStructure.TIM_Pulse = CH_Val;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
	TIM_OC1Init(TIM3, &TIM_OCInitStructure);
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
	if(enable)
	{
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	}else
	{
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
	}
	TIM_OCInitStructure.TIM_Pulse = CH_Val;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);
	
	TIM_SetCounter(TIM3, 0X0);
	TIM_SetCompare1(TIM3, 0X0);
	TIM_SetCompare2(TIM3, phase);
	
	TIM_Cmd(TIM3,ENABLE);
	TIM_ITConfig( TIM3, TIM_IT_CC1 | TIM_IT_CC2,ENABLE);
		
}
///////////////////   LED   ///////////////////////////
void LED_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = 0XFF00;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

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

 

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