第五届蓝桥杯嵌入式----双路输出控制器

代码下载地址
完成了所有要求功能

1. 功能简述

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

2. 独立按键功能

题目要求是:

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

使用外部终端判断按键按下,并进行相应处理:

usart2:

u8 K1=1;
u8 K3=1;

void KEY_Init()
{
    EXTI_InitTypeDef   EXTI_InitStructure;
    GPIO_InitTypeDef   GPIO_InitStructure;
    NVIC_InitTypeDef   NVIC_InitStructure;

  /* Enable GPIOA clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);


  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource8);
    EXTI_InitStructure.EXTI_Line=EXTI_Line8;
    EXTI_Init(&EXTI_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
    NVIC_Init(&NVIC_InitStructure);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
    EXTI_InitStructure.EXTI_Line=EXTI_Line1;
    EXTI_Init(&EXTI_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_Init(&NVIC_InitStructure);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource2);
    EXTI_InitStructure.EXTI_Line=EXTI_Line2;
    EXTI_Init(&EXTI_InitStructure);
    NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
    NVIC_Init(&NVIC_InitStructure);
}

void EXTI0_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line0) != RESET)
  {
        delay_ms(5);
        if(KEY1==0)
        {
            if(K1==0)
            {
                K1=1;
                TIM_SetCompare2(TIM2,A1_pwm);
            }
            else
            {
                K1=0;
                TIM_SetCompare2(TIM2,0);
            }
        }//while(KEY1==0);
        EXTI_ClearITPendingBit(EXTI_Line0);
  }
}

void EXTI9_5_IRQHandler(void)
{
    u8 val;
  if(EXTI_GetITStatus(EXTI_Line8) != RESET)
  {
        delay_ms(10);
        if(KEY2==0)
        {
            if(A1_pwm<899)
            {
                A1_pwm+=90;
                TIM_SetCompare2(TIM2,A1_pwm);
                x24c02_write_u16(0X01,A1_pwm);
                delay_ms(2);
            }
        }//while(KEY2==0);
    EXTI_ClearITPendingBit(EXTI_Line8);
  }
}

void EXTI1_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line1) != RESET)
  {
        delay_ms(5);
        if(KEY3==0)
        {
            if(K3==0)
            {
                K3=1;
                TIM_SetCompare3(TIM2,A2_pwm);
                LED_Control(LED2,1);
            }
            else
            {
                K3=0;
                TIM_SetCompare3(TIM2,0);
            }
        }//while(KEY3==0);
        EXTI_ClearITPendingBit(EXTI_Line1);
  }
}


void EXTI2_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line2) != RESET)
  {
        delay_ms(5);
        if(KEY4==0)
        {
            if(A2_pwm<899)
            {
                A2_pwm+=90;
                TIM_SetCompare3(TIM2,A2_pwm);
                x24c02_write_u16(0X04,A2_pwm);
                delay_ms(2);
            }
        }//while(KEY4==0);

    EXTI_ClearITPendingBit(EXTI_Line2);

  }
}

3. 串口通讯单元

题目要求是:
系统可通过串口接收命令,用户输入字符串“hh:mm:ss-PAx-yS”,设定 PAx 通道在 hh
时 mm 分 ss 秒输出脉宽调制信号,持续输出 y 秒(10>y>0) 。使用 STM32 USART2 完成上述串口功能,并将通讯波特率设定为 9600。
[命令格式举例] - 通过串口输入“00:00:20-PA1-5S” ,即设定系统在 0 时 0 分 20 秒通过
PA1 通道持续输出脉宽调制信号,5 秒后输出低电平信号。

使用了usart2,来接收上位机传来的命令,再通过Timer4,每过0.5s判断一次命令是否需要执行

u8 usart_index=0;
u8 usart_receive=0;
u8 usart_str[20];

void USART2_Init()
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);


  /* Configure USARTy Rx as input floating */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure); 

  /* Configure USARTy Tx as alternate function push-pull */
  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);

    USART_InitStructure.USART_BaudRate = 9600;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART2, &USART_InitStructure);


    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);


  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);

  USART_Cmd(USART2, ENABLE);

}



void USART2_IRQHandler(void)
{
    u8 temp;
  if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
  {
    USART_ClearITPendingBit(USART2,USART_IT_RXNE);

        temp=USART_ReceiveData(USART2);

        if((temp=='S')||(usart_index==20))
        {
            usart_str[usart_index]=temp;
            usart_index=0;
            usart_receive=1;
            USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
        }
        else
        {
            usart_str[usart_index]=temp;
            ++usart_index;
        }
  }
}

Timer3:

u8 flag_L2=0;
u8 str_com[20];
u8 command=0;
u8 fenxi=0;
u8 timedelay;

void TIM3_Init(u16 arr, u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);


    TIM_TimeBaseStructure.TIM_Period = arr;
  TIM_TimeBaseStructure.TIM_Prescaler = psc;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

     TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);



    NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the TIM2 global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

    TIM_Cmd(TIM3, ENABLE);
}


void TIM3_IRQHandler()
{
    u8 i;
    u8 str[20];
    u8 same=0;
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
        time=RTC_GetCounter();
        if(usart_receive==1&&command==0)//½ÓÊÕÊÇ·ñÕýÈ·
        {
            if((usart_str[0]=='0'||'1')&&
                (usart_str[1]=='0'||'1'||'2'||'3'||'4')&&
                (usart_str[2]==':')&&
                (usart_str[3]=='0'||'1'||'2'||'3'||'4'||'5')&&
                (usart_str[4]=='0'||'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9')&&
                (usart_str[5]==':')&&
                (usart_str[6]=='0'||'1'||'2'||'3'||'4'||'5')&&
                (usart_str[7]=='0'||'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9')&&
                (usart_str[8]=='-')&&
                (usart_str[9]=='P')&&
                (usart_str[10]=='A')&&
                (usart_str[11]=='1'||'2')&&
                (usart_str[12]=='-')&&
                (usart_str[13]=='1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9')&&
                (usart_str[14]=='S'))
            {
                command=1;
            }
            else
            {
                usart_index=0;
                usart_receive=0;
                USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
            }
        }
        if(command==1&&fenxi==0)//·ÖÎö
        {
            sprintf(str,"%0.2d:%0.2d:%0.2d",time/3600,(time%3600)/60,(time%3600)%60);
            for(i=0;i<8;i++)
            {
                if(str[i]==usart_str[i]) same=1;
                else {same=0;break;}
            }
            if(same==1)
            {
                timedelay=(usart_str[13]-'0')*2;
                fenxi=1;
            }
        }
        if(fenxi==1)//Ö´ÐÐ
        {
            timedelay--;
            if(timedelay==0)
            {
                if(usart_str[11]=='1')
                {
                    K1=1;
                    TIM_SetCompare2(TIM2,A1_pwm);

                }
                else if(usart_str[11]=='2')
                {
                    K3=1;
                    TIM_SetCompare3(TIM2,A2_pwm);
                }
                fenxi=0;
                usart_receive=0;
                command=0;
                USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
            }
        }
            if(flag_L2==1){LED_Control(LED8,1);flag_L2=0;}
            else{LED_Control(LED8,0);flag_L2=1;}
  }
}

3. LCD 显示单元显示单元

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

第五届蓝桥杯嵌入式----双路输出控制器_第2张图片

显示函数:

void window1()
{
    u8 str1[20],str2[20],str3[20],str4[20],str5[20];
    LCD_ClearLine(Line1);
    sprintf(str1," PWM-PA1: %d%%",(int)(A1_pwm+1)/9);
    LCD_DisplayStringLine(Line1,str1);
    LCD_ClearLine(Line2);
    sprintf(str2," PWM-PA2: %d%%",(int)(A2_pwm+1)/9);
    LCD_DisplayStringLine(Line2,str2);


    LCD_ClearLine(Line4);
    sprintf(str3," Time: %0.2d: %0.2d: %0.2d",time/3600,(time%3600)/60,(time%3600)%60);
    LCD_DisplayStringLine(Line4,str3);

    LCD_ClearLine(Line5);
    if(K1==1&&K3==1)
    {
        sprintf(str4," Channel: PA1 & PA2");
    }
    else if(K1==1)
    {
        sprintf(str4," Channel: PA1");
    }
    else if(K3==1)
    {
        sprintf(str4," Channel: PA2");
    }
    else
    {
        sprintf(str4," Channel: ");
    }
    LCD_DisplayStringLine(Line5,str4);


    LCD_DisplayStringLine(Line7," Command: ");

    LCD_ClearLine(Line8);
    if(command==1)
    {
        sprintf(str5,"   %s",usart_str);
    }
    else
    {
        sprintf(str5,"        None      ");
    }
    LCD_DisplayStringLine(Line8,str5);
}

4. EEPROM 数据存储单元

E2PROM的写和读,包括读写16位的数据:

void x24c02_write(u8 address,u8 data)
{
    I2CStart();
    I2CSendByte(0xa0);
    I2CWaitAck();

    I2CSendByte(address);
    I2CWaitAck();
    I2CSendByte(data);
    I2CWaitAck();
    I2CStop();
}

u8 x24c02_read(u8 address)
{
    u8 data;
    I2CStart();
    I2CSendByte(0xa0);
    I2CWaitAck();

    I2CSendByte(address);
    I2CWaitAck();

    I2CStart();
    I2CSendByte(0xa1);
    I2CWaitAck();
    data=I2CReceiveByte();
    I2CSendAck();
    I2CStop();

    return data;
}

u16 x24c02_write_u16(u8 address,u16 data)
{
    union con a;
    a.i=data;
    x24c02_write(address,a.c[0]);
    delay_ms(2);
    address++;
    x24c02_write(address,a.c[1]);
    delay_ms(2);
}

u16 x24c02_read_u16(u8 address)
{
    union con a;
    a.c[0]=x24c02_read(address);
    delay_ms(2);
    address++;
    a.c[1]=x24c02_read(address);
    return a.i;

}

5. LED 指示功能

题目要求:
通道 PA1 输出脉宽调制信号时,指示灯 LD1 点亮,其余指示灯处于熄灭状态;
通道 PA2 输出脉宽调制信号时,指示灯 LD2 点亮,其余指示灯处于熄灭状态。

在主函数中循环判断点灯:

LED_Control(LEDALL,0);
            if(K1==0)
            {
                LED_Control(LED1,0);
            }
            else
            {
                LED_Control(LED1,1);
            }
            if(K3==0)
            {
                LED_Control(LED2,0);
            }
            else
            {
                LED_Control(LED2,1);    
            }

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

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

系统时钟用RTC,PA1,PA2输出频率初始为零,设置变量可调,在按键中可改变频率

RTC:

void RTC_Init()
{
    /* Enable PWR and BKP clocks */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

  /* Allow access to BKP Domain */
  PWR_BackupAccessCmd(ENABLE);

  /* Reset Backup Domain */
  BKP_DeInit();

  /* Enable the LSI OSC */
  RCC_LSICmd(ENABLE);
  /* Wait till LSI is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET)
  {}
  /* Select the RTC Clock Source */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

  /* Enable RTC Clock */
  RCC_RTCCLKCmd(ENABLE);

  /* Wait for RTC registers synchronization */
  RTC_WaitForSynchro();

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

  /* Enable the RTC Second */
  RTC_ITConfig(RTC_IT_SEC, ENABLE);

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

  /* Set RTC prescaler: set RTC period to 1sec */
  RTC_SetPrescaler(40000);

  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

    RTC_SetCounter(23*3600+59*60+50);
}



void RTC_IRQHandler(void)
{
  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
  {
    RTC_ClearITPendingBit(RTC_FLAG_SEC);
        if(RTC_GetCounter()>=86400)
        {
            RTC_SetCounter(0);
        }
  }

两路PWM初始化:

void PWM_Init(u16 arr, u16 psc)
{
    GPIO_InitTypeDef   GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  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_TimeBaseStructure.TIM_Period = arr;
  TIM_TimeBaseStructure.TIM_Prescaler = psc;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OC2Init(TIM2, &TIM_OCInitStructure);

  TIM_OC3Init(TIM2, &TIM_OCInitStructure);

    TIM_Cmd(TIM2, ENABLE);

    //TIM_CtrlPWMOutputs(TIM2, ENABLE);

  //TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);

}

你可能感兴趣的:(嵌入式)