蓝桥杯嵌入式第四届省赛——“双路输出控制器”旧板标准库

6 篇文章 0 订阅
6 篇文章 0 订阅

一、赛题分析

        “双路输出控制器”具有信号输出时间设定、输出信号占空比调整、当前输出通道及时 间显示、系统工作参数存储、串口通讯及 LED 指示等功能。

        按照题目要求,PA1、PA2输出相同频率不同占空比PWM波,并且加入按键控制占空比和LED表示相应PWM输出引脚。USART可以定时控制引脚输出PWM波,和输出时间。再此加上EEPROM存储占空比数据。

二、程序设计

        程序中的LED、KEY、IIC、TIM4中断初始化都可以在上一篇文章中找到:

蓝桥杯嵌入式——第三届省赛“里程仪”旧板标准库_对愁眠后霜满天的博客-CSDN博客

        或者在文章最后直接下载工程,这里不再详细赘述。

1、USART2初始化

        在接收中断处,把S定为接收完毕标志位。

#ifndef _USART_H_
#define _USART_H_

#include "stm32f10x.h"
#include "stdio.h"

extern uint8_t RXOVER;
extern uint8_t RXCUNT;

extern u8 USART_RXBUF[20];

void USART2_Init(unsigned long ulBaud);

unsigned char USART_SendChar(USART_TypeDef* USARTx, unsigned char ucChar);
void USART_SendString(USART_TypeDef* USARTx, unsigned char* pucStr);

#endif
#include "stm32f10x_usart.h"
#include "usart.h"
#include "string.h"

uint8_t RXOVER = 0;
uint8_t RXCUNT = 0;

u8 USART_RXBUF[20];


void USART2_Init(unsigned long ulBaud)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStruct;
	
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	
//  //PA2用作PWM输出,所以把这段注释掉
//  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 = ulBaud;
  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);
	
  USART_Cmd(USART2,ENABLE);
	
  USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
	
  NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
  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)//此处为串口接收中断
{
  if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET)
  {
    USART_ClearITPendingBit(USART2,USART_IT_RXNE);		
    USART_RXBUF[RXCUNT++] = USART_ReceiveData(USART2);
    if(USART_RXBUF[14] == 'S' || USART_RXBUF[15] == 'S')
    {
      USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
      RXOVER = 1;
    }
  }
}

2、PA1、PA2输出相同频率不同占空比PWM波

        根据题目要求,PA1、PA2不会同时输出PWM波。一个输出PWM波,另一个输出低电平。

#ifndef _PWM_H
#define _PWM_H

#include "stm32f10x.h"

void TIM2_Configuration(u8 PA1,FunctionalState PA1State, u8 PA2,FunctionalState PA2State);

#endif

/*********************************************

PA1--TIM2--CH2   PA2--TIM2--CH3   PA3--TIM2--CH4 
PA6--TIM3--CH1   PA7--TIM3--CH2

*********************************************/
#include "pwm.h"
#include "stm32f10x_tim.h"

void TIM2_Configuration(u8 PA1,FunctionalState PA1State, u8 PA2,FunctionalState PA2State)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);

  if(PA1 == 0 || PA1State == DISABLE)
  {
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GPIOA->ODR &= ~GPIO_Pin_1;
  }else if(PA1 == 10)
  {
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GPIOA->ODR |= GPIO_Pin_1;		
  }else
  {
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);		
  }

  if(PA2 == 0 || PA2State == DISABLE)
  {
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GPIOA->ODR &= ~GPIO_Pin_2;
  }else if(PA2 == 10)
  {
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GPIOA->ODR |= GPIO_Pin_2;		
  }else
  {
    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);		
  }
	
  TIM_DeInit(TIM2);
	
  TIM_TimeBaseStructure.TIM_Period = 999;
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  /* PWM1 Mode configuration: Channel2 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = PA1*100;//占空比设置
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC2Init(TIM2, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);

  /* PWM1 Mode configuration: Channel3 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = PA2*100;//占空比设置
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC3Init(TIM2, &TIM_OCInitStructure);

  TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);

  TIM_ARRPreloadConfig(TIM2, ENABLE);

  TIM_Cmd(TIM2, ENABLE);
}

3、RTC时钟

        在主函数中初始化后直接调用update_time();显示time_str即可在相应位置显示时钟。

#ifndef __RTC_H
#define __RTC_H

#include "stm32f10x.h"

extern u8 time_str[20];
extern u8 _h,_m,_s;

void RTC_Init(u8 hh,u8 mm,u8 ss);
void RTC_Time_Get(void);
void update_time(void);
void RTC_IRQHandler(void);

#endif
#include "rtc.h"
#include "stdio.h"
#include "stm32f10x_rtc.h"
#include "misc.h"
#include "stm32f10x_bkp.h"
#include "stm32f10x_pwr.h"

u32 rtctime_value = 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 = 1;
  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_ITConfig(RTC_IT_SEC,ENABLE);
  RTC_WaitForLastTask(); 

  RTC_WaitForSynchro();
  RTC_WaitForLastTask();
	
  RTC_SetPrescaler(40000 - 1); 
  RTC_WaitForLastTask();
	
  RTC_SetCounter(hh * 3600 + mm * 60 + ss);
  rtctime_value = hh * 3600 + mm * 60 + ss;
  RTC_WaitForLastTask();
}

u8 RTC_Flag = 0;

void RTC_Time_Get(void)
{
  if(RTC_Flag)
  {
    RTC_Flag = 0;
    rtctime_value = RTC_GetCounter();
  }
}

u8 _h = 0,_m = 0,_s = 0;
u8 time_str[20] = {0};

void update_time(void)
{
  RTC_Time_Get();
  _h = rtctime_value / 3600;
  _m = (rtctime_value % 3600) / 60;
  _s = rtctime_value % 3600 % 60;
  sprintf((char*)time_str, "  Timer: %02d:%02d:%02d   ", _h, _m, _s);
}

void RTC_IRQHandler(void)
{
  u32 times;
  if(RTC_GetITStatus(RTC_IT_SEC == 1))
  {
    times = RTC_GetCounter();
    RTC_Flag = 1;
    if(times == (24 * 3600 - 1))
    {
      RTC_SetCounter(0);
      RTC_WaitForLastTask();	
    }
    RTC_ClearITPendingBit(RTC_IT_SEC);
  }
}

4、main.c

#include "stm32f10x.h"
#include "lcd.h"
#include "led.h"
#include "key.h"
#include "rtc.h"
#include "delay.h"
#include "timer.h"
#include "pwm.h"
#include "i2c.h"
#include "usart.h"
#include "stdio.h"
#include "string.h"

#define PWM_ENABLE 0
#define UART_ENABLE 1

u8 PA1_duty = 8,PA2_duty = 1,channel_flag = 0,flag = 0;
FunctionalState PA1_stat = DISABLE;
FunctionalState PA2_stat = DISABLE;
u8 led_flag = 0,key_flag = 0,usart_flag = 0,arrive_flag = 0;
u8 key1_flag = 0,key3_flag = 0;
u8 string[20],us[20];
u16 time_cnt = 0;
float adc_temp;

void show_main(void);
void usart_proc(void);
void key_in(void);
void PWM_UART_Enable(u8 flag);

//Main Body
int main(void)
{
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
  STM3210B_LCD_Init();      
  LCD_Clear(Black);          
  LCD_SetBackColor(Black);   
  LCD_SetTextColor(White);  

  SysTick_Config(SystemCoreClock/1000);
	
  TIM4_Init();
  USART2_Init(9600);
  PWM_UART_Enable(1);//处DISABLE PWM,先选择USART ENABLE
  TIM2_Configuration(PA1_duty,PA1_stat,PA2_duty,PA2_stat);
  LED_Init();
  KEY_Init();
  i2c_init();
  RTC_Init(23,59,50);
	
  //存储功能
  if(i2c_read(0x11)<=10)
    PA1_duty = i2c_read(0x11);
  else PA1_duty = 8;
	
  if(i2c_read(0x12)<=10)
    PA2_duty = i2c_read(0x12);
  else PA2_duty = 1;
  while(1)
  {
    key_in();
    show_main();
    usart_proc();
    if(arrive_flag == 1)//完毕后,PWM全部DISABLE,USART打开,LED全部熄灭,us清0.
    {
      arrive_flag = 0;
      PA1_stat = DISABLE;PA2_stat = DISABLE;
      PWM_UART_Enable(1);
      channel_flag = 0;	  
      TIM2_Configuration(PA1_duty,PA1_stat,PA2_duty,PA2_stat);
      LED_Control(LED1|LED2,0);
      memset(us,0,sizeof(us));
    }
  }
}

/*
在key_in中,每按下按键一次,程序只执行一次。在这里选择输出PWM波引脚
因为USART于PWM冲突,在串口打开时,PA2无PWM输出
所以要输出PWM波时要DISABLE USART,同理等待接收数据时要DIASBLE PWM
*/
void key_in(void)
{
  key_flag = key_scan();
  //KEY1
  if(key_flag == 1&&key3_flag == 0)
  {
    key1_flag =! key1_flag;
    if(key1_flag == 0)
    {
      channel_flag = 0;
      LED_Control(LED1,0);
      PA1_stat = DISABLE;PA2_stat = DISABLE;
      PWM_UART_Enable(1);
      TIM2_Configuration(PA1_duty,PA1_stat,PA2_duty,PA2_stat);
    }
    if(key1_flag == 1)
    {
      channel_flag = 1;
      LED_Control(LED1,1);
      PA1_stat = ENABLE;PA2_stat = DISABLE;
      PWM_UART_Enable(0);
      TIM2_Configuration(PA1_duty,PA1_stat,PA2_duty,PA2_stat);
    }
  }
	
  //KEY2
  if(key_flag == 2&&key1_flag == 1)
  {
    PA1_duty = (PA1_duty + 1)%11;
    i2c_write(0x11,PA1_duty);Delay_Ms(10);
    TIM2_Configuration(PA1_duty,PA1_stat,PA2_duty,PA2_stat);
  }
	
  //KEY3
  if(key_flag == 3&&key1_flag == 0)
  {
    key3_flag =! key3_flag;
    if(key3_flag == 0)
    {
      channel_flag = 0;
      LED_Control(LED2,0);
      PA1_stat = DISABLE;PA2_stat = DISABLE;
      PWM_UART_Enable(1);
      TIM2_Configuration(PA1_duty,PA1_stat,PA2_duty,PA2_stat);			
    }
    if(key3_flag == 1)
    { 
      channel_flag = 2;
      LED_Control(LED2,1);
      PA1_stat = DISABLE;PA2_stat = ENABLE;
      PWM_UART_Enable(0);
      TIM2_Configuration(PA1_duty,PA1_stat,PA2_duty,PA2_stat);
    }
  }
	
  //KEY4
  if(key_flag == 4&&key3_flag == 1)
  {
    PA2_duty = (PA2_duty + 1)%11;
    i2c_write(0x12,PA2_duty);Delay_Ms(10);
    TIM2_Configuration(PA1_duty,PA1_stat,PA2_duty,PA2_stat);		
  }
}

void show_main(void)
{
  memset(string,0,sizeof(string));
  sprintf((char*)string,"  PWM-PA1: %d %%    ",PA1_duty*10);
  LCD_DisplayStringLine(Line1,string);
	
  memset(string,0,sizeof(string));
  sprintf((char*)string,"  PWM-PA2: %d %%    ",PA2_duty*10);
  LCD_DisplayStringLine(Line3,string);
	
  update_time();
  LCD_DisplayStringLine(Line5,(u8*)time_str);		
	
  switch(channel_flag)
  {
    case 0: LCD_DisplayStringLine(Line6,(u8*)"  Channel:            ");break;
    case 1: LCD_DisplayStringLine(Line6,(u8*)"  Channel: PA1            ");break;
    case 2: LCD_DisplayStringLine(Line6,(u8*)"  Channel: PA2           ");break;
    default: break;
  }
	
  LCD_DisplayStringLine(Line8,(u8*)"  Command:             ");
	
  memset(string,0,sizeof(string));
  sprintf((char*)string,"  %s ",us);
  LCD_DisplayStringLine(Line9,string);
  if(*us == 0)
    LCD_DisplayStringLine(Line9,(u8*)"         None            ");
}

/*
串口接收函数,把接收到的数据幅值给 us,然后清零USART_RXBUF
只有us响应后us清0后再次打开串口接收
*/
void usart_proc(void)
{
  u8 i;
  if(RXOVER == 1 && *us == 0)
  {
    RXOVER = 0;
    RXCUNT = 0;
    for(i = 0;i<20;i++)
    {
      us[i]=USART_RXBUF[i];
      if(us[i] == 'S')break;
    }
    memset(USART_RXBUF,0,sizeof(USART_RXBUF));
  }
	
  if((us[0]-48)*10+us[1]-48==_h&&(us[3]-48)*10+us[4]-48==_m&&(us[6]-48)*10+us[7]-48==_s&&us[14] == 'S')
  {
    if(us[11]-48 == 1)//满足条件后,关闭USART,选择PWM输出
    {
      channel_flag = 1;
      PA1_stat = ENABLE;PA2_stat = DISABLE;
      PWM_UART_Enable(0);
      TIM2_Configuration(PA1_duty,PA1_stat,PA2_duty,PA2_stat);			
   }else if(us[11]-48 == 2)
    {
      channel_flag = 2;
      PA1_stat = DISABLE;PA2_stat = ENABLE;
      PWM_UART_Enable(0);
      TIM2_Configuration(PA1_duty,PA1_stat,PA2_duty,PA2_stat);				
    }
    time_cnt = (us[13]-48)*1000;//倒计时时间
    usart_flag = 1;//中断开始标志位
  }
  if(usart_flag == 1)
  {
    if(channel_flag == 1)LED_Control(LED1,1);
    if(channel_flag == 2)LED_Control(LED2,1);
  }
}

//USART PWM 选择函数,如果两者冲突则PA2无PWM输出
void PWM_UART_Enable(u8 flag)
{
  if(flag==PWM_ENABLE)
  {
    USART_Cmd(USART2, DISABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 | RCC_APB2Periph_AFIO, DISABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB2Periph_AFIO, ENABLE);	
    TIM_Cmd(TIM2, ENABLE);
  }
	
  if(flag==UART_ENABLE)
  {
    TIM_Cmd(TIM2, DISABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB2Periph_AFIO, DISABLE);		
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 | RCC_APB2Periph_AFIO, ENABLE);
    USART_Cmd(USART2, ENABLE);
  }
}

void TIM4_IRQHandler(void)
{
  static u16 T_cnt = 0;
  if(TIM_GetITStatus(TIM4,TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
    if(usart_flag == 1)
    {
      if(++T_cnt>=time_cnt)
      {
        usart_flag = 0;
        T_cnt = 0;
        arrive_flag = 1;//倒计时完毕标志位
      }
    }
  }
}

三、附上工程

链接:https://pan.baidu.com/s/1Fg3Uevz-e38MwdstCw-GuA 
提取码:fuie

有不对的地方,请多指教...

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

对愁眠后霜满天

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

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

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

打赏作者

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

抵扣说明:

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

余额充值