蓝桥杯嵌入式开发经验分享(第五届模拟——“双路输出控制器”)

作者:马一飞                                                         QQ:791729359       

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

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

一、题目

        “双路输出控制器”具有信号输出时间设定、输出信号占空比调整、当前输出通道及时间显示、系统工作参数存储、串口通讯及 LED 指示等功能。“双路输出控制器”通过串口完成信号输出时间设定功能;通过 EEPROM 完成系统工作参数存储功能;通过按键完成输出通道切换、输出信号占空比调整及停止信号输出功能;系统硬件电路主要由 MCU 控制单元、独立按键、LCD 显示单元、串口通讯单元、EEPROM 数据存储单元和 LED 指示单元组成,系统框图如图 1 所示:

                                             

设计任务及要求

1. 独立按键功能

1.1 按下 B1 按键,PA1 输出脉宽调制信号,再次按下 B1,PA1 持续输出低电平,如此循环;
1.2 B2 按键功能设定为通道 PA1 输出脉宽调制信号占空比调整,按下 B2,通道 PA1 输出信号占空比以 10%步进,调整后的输出信号占空比将保存至 EEPROM 中;
1.3 按下 B3 按键,PA2 输出脉宽调制信号,再次按下 B3,PA2 持续输出低电平,如此循环;
1.4 B4 按键功能设定为通道 PA2 输出脉宽调制信号占空比调整,按下 B4,通道 PA2 输出信号占空比以 10%步进,调整后的输出信号占空比将保存至 EEPROM 中。

2. 串口通讯单元

        系统可通过串口接收命令,用户输入字符串“hh:mm:ss-PAx-yS”,设定 PAx 通道在 hh时 mm 分 ss 秒输出脉宽调制信号,持           续输出 y 秒(0<y<10)。使用 STM32 USART2 完成上述串口功能,并将通讯波特率设定为 9600。

        [命令格式举例] - 通过串口输入“00:00:20-PA1-5S”,即设定系统在 0 时 0 分 20 秒通过
        PA1 通道持续输出脉宽调制信号,5 秒后输出低电平信号。

3. LCD 显示单元

       通过 LCD 显示当前 EEPROM 中存储的脉宽调制信号占空比、系统时间、当前正在输出的通道以及通过串口接收到的命令,LCD 显示界面参考示意图如图 2、图 3 所示:

                           

4. EEPROM 数据存储单元

        通过 EEPROM 存储 PA1、PA2 输出信号的占空比,占空比数值可以通过按键调整。

5. LED 指示功能
        通道 PA1 输出脉宽调制信号时,指示灯 LD1 点亮,其余指示灯处于熄灭状态;
        通道 PA2 输出脉宽调制信号时,指示灯 LD2 点亮,其余指示灯处于熄灭状态。

6. 系统工作及初始化状态说明

        系统初始化时间设定为 23 时 59 分 50 秒,PA1、PA2 输出频率固定为 1KHz,串口通讯波特率设定为 9600 bps。

二、模块化代码分析

1、初始化部分

#include "stm32f10x.h"
#include "lcd.h"
#include "stdio.h"
#include "i2c.h"
#include "IO.h"
u32 TimingDelay = 0;
u8 RXCUNT = 0;
u8 RXOVER = 0;
u8 RXBUF[20];
u8 i;
u8 key_Flag = 0;
u8 string[20];
u8 RTC_Read = 0;
u32 TimeVal;
u8 hour,min,sec;
u8 RX_hour,RX_min,RX_sec,RX_ch,RX_delay;
u8 LED_Flag = 0;
u8 A1_Duty = 10,A2_Duty = 10;
extern u8 CH2_OutPut,CH3_OutPut;
extern u16 LED_MODE;
void Delay_Ms(u32 nTime);
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);
LED_Init();
KEY_Init();
RTC_Init(23,59,55);
A1_Duty = _24c02_read(0xaa);
A2_Duty = _24c02_read(0xbb);
TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,1,0,0);
LCD_DisplayStringLine(Line9, "None");
LCD_DisplayStringLine(Line8, "  Command : ");

2、串口部分

if(RXOVER == 1)
{
	//USART2_SendString(RXBUF);
	RX_hour =(RXBUF[0] - 0x30) * 10 + (RXBUF[1] - 0x30);
	RX_min = (RXBUF[3] - 0x30) * 10 + (RXBUF[4] - 0x30);
	RX_sec = (RXBUF[6] - 0x30) * 10 + (RXBUF[7] - 0x30);
	RX_ch = RXBUF[11] - 0x30;
	LCD_ClearLine(Line9);
	LCD_DisplayStringLine(Line9, RXBUF);
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	RXOVER = 0;
}

3、按键部分

if(key_Flag == 1)  // 50ms
{
	KEY_Read();
	key_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)
		{
			CH2_OutPut ^= 1;
		    TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
		}
	}else
	{
		key1_sum = 0;
	}
	
	if(KEY2 == 0)
	{
		key2_sum++;
		if(key2_sum == 1)
		{
			A1_Duty += 10;
			if(A1_Duty == 100)
			{
				A1_Duty = 10;
			}
			_24c02_write(0xaa,A1_Duty);
			TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
		}
	}else
	{
		key2_sum = 0;
	}
	
	if(KEY3 == 0)
	{
		key3_sum++;
		if(key3_sum == 1)
		{
			CH3_OutPut ^= 1;
			TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
		}
	}else
	{
		key3_sum = 0;
	}
		
	if(KEY4 == 0)
	{
		key4_sum++;
		if(key4_sum == 1)
		{
			A2_Duty += 10;
			if(A2_Duty == 100)
			{
				A2_Duty = 10;
			}
			_24c02_write(0xbb,A1_Duty);
			TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
		}
	}else
	{
		key4_sum = 0;
	}
}

4、RTC部分

if(RTC_Read == 1)
{
					
	TimeVal = RTC_GetCounter();
	hour = TimeVal / 3600;
	min = TimeVal % 3600 / 60;
	sec = TimeVal % 3600 % 60;
	if(TimeVal == (RX_hour * 3600 + RX_min * 60 + RX_sec))
	{
		RX_delay = RXBUF[13] - 0x30;
		if(RX_ch == 1)
		{
			CH2_OutPut = 1;
		}
		if(RX_ch == 2)
		{
			CH3_OutPut = 1;
		}
		TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
	}
	if(!RX_delay)
	{
		if(RX_ch == 1)
		{
			CH2_OutPut = 0;
		}
		if(RX_ch == 2)
		{
			CH3_OutPut = 0;
		}
		TIM2_PA1_PWM_Init(A1_Duty,A2_Duty,0,CH2_OutPut,CH3_OutPut);
		for(i = 0;i < 20;i++)
		{
			RXBUF[i] = 0;
		}
	}
	RTC_Read = 0;
}

5、LED部分

if(LED_Flag)
{
	if(CH2_OutPut)
	{
		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);
	}
					
	if(CH3_OutPut)
	{
		LED_MODE &= ~(1<<9);
		GPIOC->ODR = LED_MODE;
		GPIOD->ODR |= (1<<2);
		GPIOD->ODR &=~(1<<2);
	}else
	{
		LED_MODE |= (1<<9);
		GPIOC->ODR = LED_MODE;
		GPIOD->ODR |= (1<<2);
		GPIOD->ODR &=~(1<<2);
	}
}

6、LCD显示

sprintf((char *)string,"  PWM-PA1 : %d %%    ",A1_Duty);
LCD_DisplayStringLine(Line1, string);
sprintf((char *)string,"  PWM-PA2 : %d %%    ",A2_Duty);
LCD_DisplayStringLine(Line3, string);
sprintf((char *)string,"  TIME : %.2d:%.2d:%.2d ",hour,min,sec);
LCD_DisplayStringLine(Line5, string);
if(CH2_OutPut && CH3_OutPut)
{
	sprintf((char *)string,"  Channel : PA1 PA2        ");
	LCD_DisplayStringLine(Line6, string);
}else
if(CH2_OutPut)
{
	sprintf((char *)string,"  Channel : PA1            ");
	LCD_DisplayStringLine(Line6, string);
}else
if(CH3_OutPut)
{
	sprintf((char *)string,"  Channel : PA2            ");
	LCD_DisplayStringLine(Line6, string);
}else
{
	sprintf((char *)string,"  Channel :                ");
	LCD_DisplayStringLine(Line6, string);
}

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

void USART2_IRQHandler(void)
{
	u8 temp;
	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)
{
	while(RTC_GetITStatus(RTC_IT_SEC) == 1)
	{
		RTC_ClearITPendingBit(RTC_IT_SEC);
		RTC_Read = 1;
		if(RTC_GetCounter() == (24 * 3600))
		{
			RTC_SetCounter(0x0);
			RTC_WaitForLastTask();
		}
	}
}
void SysTick_Handler(void)
{
	static u8 key_sum = 0;
	static u16 second_sum = 0;
	static u8 LED_sum = 0;
	TimingDelay--;
	if(++key_sum == 50)   //50ms
	{
		key_sum = 0;
		key_Flag = 1;
	}
	
	if(++second_sum == 1000)  //1s
	{
		second_sum = 0;
		if(RX_delay) RX_delay--;
	}
	
	if(++LED_sum == 200)  // 200ms
	{
		LED_sum = 0;
		LED_Flag = 1;
	}
}

三、通用初始化部分

#include "IO.h"
u16 LED_MODE = 0XFFFF;
extern u8 A1_Duty,A2_Duty;
u8 CH2_OutPut = 0,CH3_OutPut = 0;
///  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();
	
	return temp;
}


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_Mode = USART_Mode_Rx;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init(USART2,&USART_InitStructure);
		
	USART_Cmd(USART2, ENABLE);
		
	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_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_GPIOC | RCC_APB2Periph_GPIOD,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);
}

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_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/   RTC  //
void RTC_Init(u8 HH,u8 MM,u8 SS)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);
	PWR_BackupAccessCmd(ENABLE);
	BKP_DeInit();
	
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	RCC_LSICmd(ENABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0);
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
	RCC_RTCCLKCmd(ENABLE);
	
	RTC_WaitForSynchro();		
    RTC_WaitForLastTask();			

    RTC_SetPrescaler(40000-1);
	RTC_WaitForLastTask();
	
	RTC_ITConfig(RTC_IT_SEC, ENABLE);
	RTC_WaitForLastTask();
	
	RTC_SetCounter(HH * 3600 + MM * 60 + SS);
	RTC_WaitForLastTask();
}
/   PWM /
void TIM2_PA1_PWM_Init(u8 duty_A1,u8 duty_A2,u8 status,u8 CH2_OPEN,u8 CH3_OPEN)
{
	u32 A1_Pluse,A2_Pluse;
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	if(status)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &GPIO_InitStructure);
				
		TIM_TimeBaseInitStructure.TIM_Period = 999;
		TIM_TimeBaseInitStructure.TIM_Prescaler = 71;
		TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
		TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
		TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	}
		
	A1_Pluse = 998 * duty_A1 / 100;
	A2_Pluse = 998 * duty_A2 / 100;
		
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
	if(CH2_OPEN)
	{
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	}else
	{
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
	}
	TIM_OCInitStructure.TIM_Pulse = A1_Pluse;
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
		
	if(CH3_OPEN)
	{
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	}else
	{
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
	}
	TIM_OCInitStructure.TIM_Pulse = A2_Pluse;
	TIM_OC3Init(TIM2,&TIM_OCInitStructure);
	if(status)
	{
		TIM_Cmd(TIM2,ENABLE);
	}
}

 

  • 12
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 26
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fei...

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值