蓝桥杯嵌入式类比赛经验分享

第八届蓝桥杯大赛(嵌入式组)

    蓝桥杯的嵌入式组是Stm32rbt6单片机的编程比赛,我想对于学习电子信息工程专业的同学这不是一个陌生的名词,如果你是电信专业的大四同学却没有听说过msp430或者stm32,或许你应该审视一下自己是否懈怠了4年时光,不过一般大四的同学是看不见我这篇文章的。

    看到这篇文章的人大多是要参加这个比赛的同学,我在上次比赛中只获得了国二,差一丢丢国一这是非常令人遗憾的事情,我会在接下来的文章中介绍我的经验,和产生遗憾的原因。
  • 竞赛板介绍

  • 竞赛板使用经验

  • 部分外设的配置

  • 要求熟练掌握的知识

  • 错失国一的自我反省

  • 客观题部分


竞赛板介绍

  • 图片展示
    蓝桥杯嵌入式类比赛经验分享_第1张图片
    蓝桥杯嵌入式类比赛经验分享_第2张图片
  • 介绍
    第一块板子是主板,第二块是扩展板,他们的资料可以通过加蓝桥杯嵌入式相关的QQ群中去下载,有空的话我也可以分享出来。

竞赛板使用经验

①下载程序并不是使用Stlink或者Jlink,而是CooCox
②使用蜂鸣器的时候是需要将PB4短接帽接上,而一般正常使用时是不可短接PB4的,否则无法下载程序。理由我就不细说了,PB4的主要功能是J-RST其复用功能才是普通IO口,我会在后面附上蜂鸣器的相关配置。

部分外设的配置

  • 在此之前我还是希望对读者的基础知识有一点小小的要求
    1.C语言功底至少在结构体之后链表之前即可。
    2.熟悉Uart,SPI,I2C三种基础通信协议(我这里的熟悉是指SPI和I2C能够盲打)

时钟配置

用到哪些外设就开启对应时钟,注意APB1和APB2所对应的外设

void RCC_Configuration(void)
{
/* TIM clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
/* GPIO clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);
}

GPIO配置

用多少添加多少

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
 /* GPIOC Configuration:Pin6, 7, 8 and 9 as alternate function push-pull */
  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  ;    //BUTTON
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

//  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_2  ;      //UASRT2T
//  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  ;    //UASRT2R
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);


  GPIO_InitStructure.GPIO_Pin =  0XFF00  ;    //LED
  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  ;    //LED
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOD, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0  ;    //adc
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4  ;    //BEER
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2  ;  //CAP
  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_6 | GPIO_Pin_7  ; //PWM_OUT
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

中断配置

哪些外设需要使用中断就在此处开启,用多少开多少

void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the TIM2 global Interrupt */
  NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1 );

  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;             //BUTTON
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority =5;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;           //USART2
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;             //RTC
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;            //Capture
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;            //PWM_OUT
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);


} 

LED灯的配置

有两处,一处是IO口的配置,一处是LED的控制

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  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);
}
void LED_Set( u8 data )
{
GPIOD->ODR |= GPIO_Pin_2;
GPIOC->ODR = ~(data<<8);
GPIOD->ODR &= ~GPIO_Pin_2;
}

按键扫描(非阻塞)

 void BUTTON_Config(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_TimeBaseStructure.TIM_Period = 10000;
  TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
  /* TIM IT enable */
  TIM_ITConfig(TIM4, TIM_IT_Update , ENABLE);
  /* TIM4 enable counter */
  TIM_Cmd(TIM4, ENABLE);
}

 #define PORTA (GPIOA->IDR)
 #define PORTB (GPIOB->IDR)
 #define BUTTON_1 GPIO_Pin_0
 #define BUTTON_2 GPIO_Pin_8
 #define BUTTON_3 GPIO_Pin_1
 #define BUTTON_4 GPIO_Pin_2

 u8 button_delay = 0;
 u8 button_sure_flog = 0;

void TIM4_IRQHandler(void)
{
    if(button_delay)button_delay--;
    else
    {
        if( (PORTA&(BUTTON_1|BUTTON_2))!= (BUTTON_1|BUTTON_2) ||
            (PORTB&(BUTTON_3|BUTTON_4))!= (BUTTON_3|BUTTON_4)   
          )
          {
                if( button_sure_flog==0 )button_sure_flog=1;
                else
                {
                    button_sure_flog=0;
                    if( (PORTA&BUTTON_1)==0 )  //B1
                    {
                        //按下B1所执行的操作
                    }
                    if( (PORTA&BUTTON_2)==0 )  //B2
                    {
                        //按下B2所执行的操作
                    }
                    if( (PORTB&BUTTON_3)==0 )  //B3
                    {
                        //按下B3所执行的操作
                    }
                    if( (PORTB&BUTTON_4)==0 )  //B4
                    {
                        //按下B4所执行的操作
                    }
                    button_delay = 20;
                }
          }else button_sure_flog=0;
    }
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
}

AT24C02读写

使用了i2c.h 就不用写i2c的基础驱动

void W_EEPROM( u8 addr ,u8 data ) //指定地址写数据
{
   u32 i=0x10000;
   I2CStart( );
   I2CSendByte(0xa0);
   I2CWaitAck( );
   I2CSendByte(addr);
   I2CWaitAck( );
   I2CSendByte(data);
   I2CWaitAck( );
   I2CStop( );
   while(i--);
}

u8 R_EEPROM( u8 addr )  //指定地址读数据
{
   u32 i=0x10000;
   u8 data=0;
   I2CStart( );
   I2CSendByte(0xa0);
   I2CWaitAck( );
   I2CSendByte(addr);
   I2CWaitAck( );
   I2CStart( );
   I2CSendByte(0xa1);
   I2CWaitAck( );
   data = I2CReceiveByte();
   I2CSendNotAck( );
   I2CStop( );
   while(i--);
   return data;
}

ADC的配置

此外还需要开启ADC的RCC时钟和IO口配置为模拟输入,这些都应该在GPIO_config中完成

void ADC_Config(void)
{
  ADC_InitTypeDef ADC_InitStructure;
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channel14 configuration */ 
 ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_5Cycles5);

  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);
  /* Enable ADC1 reset calibration register */   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));

  /* Start ADC1 calibration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));
  /* Start ADC1 Software Conversion */ 
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);   
}

u16 Get_ADC_Data(void)
{
    u8 i=10;
    u16 Result=0;
    while(i--)
    {
        ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
        while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)==RESET);
        Result+=ADC_GetConversionValue(ADC1);
    }
    return Result/10;
}

USART2的printf输出

除开还差对应的时钟和IO口配置外,还应包含头文件 stdio.h
看到下面的代码你可能会疑惑我怎么写出来的,答案是从3.5标准库中的历程复制出来加以修改的,参加蓝桥杯的同学要必须做到非常熟练的从3.5库历程中复制想要的代码

#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

/* Private functions ---------------------------------*/
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
#define EVAL_COM1 USART2

PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART */
  USART_SendData(EVAL_COM1, (uint8_t) ch);

  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TC) == RESET)
  {}
  return ch;
}

void UART_Config(u32 BaudRate)
{
  USART_InitTypeDef USART_InitStructure;

  USART_InitStructure.USART_BaudRate = BaudRate;
  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);
  USART_Cmd(USART2, ENABLE);
  USART_ITConfig(USART2, USART_IT_RXNE,  ENABLE);
}

u8 RECV_BUFF[30];
u8 RECV_CNT = 0;
u8 RECV_SUCCESS_FLOG = 0;

void USART2_IRQHandler(void)
{
   //可在此处编写UART收到数据后对数据的操作,别告诉我你不知道数据在哪里
   USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}

PWM输出

PWM输出是比赛的重点和难点,我希望你们对捕获比较寄存器有较为深刻的理解,我的这个仅供参考

void PWM_Out_Config(void)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;  
  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 65535;
  TIM_TimeBaseStructure.TIM_Prescaler = 36;    //0.5us +1
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  /* Output Compare Toggle Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 1000;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
  TIM_OC1Init(TIM3, &TIM_OCInitStructure);
  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);
  /* Output Compare Toggle Mode configuration: Channel2 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 1000;
  TIM_OC2Init(TIM3, &TIM_OCInitStructure);
  //CCRx的值在改动后立刻生效
  /* TIM enable counter */
  TIM_Cmd(TIM3, ENABLE);
  /* TIM IT enable */
  TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2 , ENABLE);
}

u16 Out_Freq_Ch1 = 1000;   //(单位us)
u16 Out_Freq_Ch2 = 1000;

void TIM3_IRQHandler(void)  //波形输出   
{
  if(TIM_GetITStatus(TIM3, TIM_IT_CC1)!=RESET)
  {
     (TIM3->CCR1)+=Out_Freq_Ch1;  
     TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);   
  }
  if(TIM_GetITStatus(TIM3, TIM_IT_CC2)!=RESET)
  {
     (TIM3->CCR2)+=Out_Freq_Ch2;   
     TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);   
  }
}

void Ch1_Out_Pwm_Set( u32 Freq_ch1 ,u8 Out_Status )  //输入的单位就是HZ
{
     GPIO_InitTypeDef GPIO_InitStructure;
     Out_Freq_Ch1 = (1000000/(Freq_ch1))-10;      //配置频率参数
     GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 ;    //PWM_OUT
     if(Out_Status==0)
     {
         TIM_ITConfig(TIM3, TIM_IT_CC1, DISABLE);
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOA, &GPIO_InitStructure);
         GPIOA->ODR &= ~GPIO_Pin_6 ;    //输出低电平
     }
     else
     {
         TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);
         GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_AF_PP ;
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOA, &GPIO_InitStructure);  //翻转输出
     }
}

void Ch2_Out_Pwm_Set( u32 Freq_ch2 ,u8 Out_Status )  //单位HZ
{
     GPIO_InitTypeDef GPIO_InitStructure;
     Out_Freq_Ch2 = (1000000/(Freq_ch2))-10;      //配置频率参数
     GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_7 ;    //PWM_OUT
     if(Out_Status==0)
     {
         TIM_ITConfig(TIM3, TIM_IT_CC2, DISABLE);
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOA, &GPIO_InitStructure);
         GPIOA->ODR &= ~GPIO_Pin_7 ;    //输出低电平
     }
     else
     {
         TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);
         GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_AF_PP ;
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOA, &GPIO_InitStructure);  //翻转输出
     }
}

PWM输入(频率占空比检测)

PWM输入也是比赛的重点和难点,我希望你们对捕获比较寄存器有较为深刻的理解,我的这个仅供参考

void PWM_Capture_Config(void)
{
  TIM_ICInitTypeDef  TIM_ICInitStructure;
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;  
  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 65535;   
  TIM_TimeBaseStructure.TIM_Prescaler = 72;   //1us +1
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICFilter = 0x0;      
  TIM_ICInit(TIM2, &TIM_ICInitStructure);

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  TIM_ICInitStructure.TIM_ICFilter = 0x0;

  TIM_ICInit(TIM2, &TIM_ICInitStructure);

  /* TIM enable counter */
  TIM_Cmd(TIM2, ENABLE);

  /* Enable the CC2 Interrupt Request */
  TIM_ITConfig(TIM2, TIM_IT_CC2|TIM_IT_CC3, ENABLE);
}

u32 Freq_Ch2_Cap = 0;     //通道2的频率 (HZ)
u32 Freq_Ch3_Cap = 0;
u16 CH2_DATA_LAST = 0;    //存放上次捕获到的数据
u16 CH3_DATA_LAST = 0;

void TIM2_IRQHandler(void)  //获取频率
{
  if(TIM_GetITStatus(TIM2, TIM_IT_CC2)!=RESET)
  {
     Freq_Ch2_Cap = 1000000/((TIM2->CCR2) - CH2_DATA_LAST);
     CH2_DATA_LAST = (TIM2->CCR2);
     TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);   
  }
  if(TIM_GetITStatus(TIM2, TIM_IT_CC3)!=RESET)
  {
     Freq_Ch3_Cap = 1000000/((TIM2->CCR3) - CH3_DATA_LAST);
     CH3_DATA_LAST = (TIM2->CCR3);
     TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);   
  }
}

蜂鸣器

注意PB4的问题,已经在GPIO的函数中配置

#define BEER_H (GPIOB->ODR |= GPIO_Pin_4)
#define BEER_L (GPIOB->ODR &= ~GPIO_Pin_4)

要求熟练掌握的知识

  • 由于第八届(我参加的这一届)是第一次出现了扩展板,我们当时是省赛不使用扩展板,国赛会用到,所以扩展版的代码我就不贴了,实在太长了,刚才还有RTC我都没有贴上来,我先说说扩展板需要熟练的东西,比赛的时候DS18B2和DHT11等是直接提供现成的驱动程序,我当时并不知道,所以我自己准备的是能够盲打扩展板上的所有外设的驱动程序,我希望读者不要因为直接提供驱动程序就不去过多关注这些外设,我个人建议你们能够做到盲打。
  • 熟练:
    能够至少输出两路占空比可调,频率固定的PWM
    能够至少输出两路频率可调,占空比固定的PWM
    能够至少输出两路频率可调,占空比可调的PWM
    能够至少检测两路PWM的频率和占空比
    能够查阅数据手册,轻松使用片上外设这IO口重映射

错失国一的自我反省

  • 这次我差一点获得国一,可能是因为比前面的人多错了一道客观题,失之毫厘差之千里,失败的原因有沉浸在自认无敌的良好状态(过于自负),决赛题目中有一个看似普通情况下是不可能完成的一道设问,我的经验直觉告诉我此时需要查阅数据手册,看看是否能够通过IO重映射来解决,答案是肯定的,我完美的解决了这个出题人的“圈套”,欣喜之下我忘乎了自己,骄傲自满认为别人都做的没自己好,于是开始懈怠。我在比赛结束还有一个小时前就完成了所有题目要求,起身提交题目转头就走,客观题检都没检查,导致了这个悲剧的发生,这种自负让我在8月的电子设计竞赛中又一次与国一失之交臂,被同伴称之为万年国二….. 不思悔改,方得(遭)始(报)终(应),望读者引以为戒。

客观题部分

  • STM32F103RBT6 基础知识 和 数电模电基础知识

64个引脚
Flash = 128 kb
Sram = 20 kb

STM32 F 103 C 8 T 6 A

F = 通用类型

103 = 增强型
101 = 基本型
102 = USB基本型,USB 2.0全速设备
105或107 = 互联型

T = 36脚
C = 48脚
R = 64脚
V = 100脚
Z = 144脚

4 = 16K 闪存存储器
6 = 32K
8 = 64K
B = 128K
C = 256K
D = 384K
E = 512K

H = BGA
T = LQFP
U = VFQFPN
Y = WLCSP64

6 = -40°C ~ 85°C
7 = -40°C ~ 105°C

A或者 空(内部代码,详见产品数据手册)

//——————————————————————–
7个TIMER = (有TIM1和TIM8)TIM1~TIM5
STM32RBT6只有4个定时器: TIM1~TIM4
2个SPI
2个I2C
2个12bit ADC
3个USART
1个USB
1个CAN
49个普通GPIO

第一部分:客观题
1.STM32F103RBT6单片机具有20___KByte RAM空间,____128__Kbyte Flash空间,______3个USART,_2___12位ADC。

2.以下哪种方法或工具可以对STM32进行程序下载( ABCD )
A. J-link
B. Co-Link
C.USART ISP
D.USART IAP

3.下面哪些描述是STM32 GPIO具备的特点( ABCD )
A. 单独的位设置、清除
B. 外部中断线/唤醒线
C. 复用功能和重映射
D.GPIO锁定机制

4.模拟信号采集设备,ADC参考电压为5V,要求分辨率达到5mV,ADC至少应选择( B )
A. 8位
B. 10位
C. 12位
D. 16位

5.STM32 DMA控制器可编程的数据传输数目最大为( D )
A.65536
B. 4096
C.1024
D. 65535

6.某系统需要永久存放少量(少于1K byte)参数,且需要频繁访问,最合适的存储器是( B )
A. SRAM
B. E2PROM
C. Nor Flash
D. Nand Flash

7.运算放大器的电源接入±12V,稳压管的稳定电压为6V,正向导通电压为0.6V,当输入电压Ui = -2V时,输出电压UO应该为( C )
A. -6V
B. -2V
C. +6V
D. 0.6V

8.以下哪几种操作系统适合在STM32系列微控制器( AB )
A. μCos-II
B. Free RTOS
C. Windows CE
D. Linux

//——————————-以下为我自己手动添加的试题———————————//
1.STM32内部提供了电压调节器,复位后电压调节器总是使能的。根据应用方式它以如下3 种不同的模式工作( D )。(多选)
A.运转模式
B.停止模式
C.待机模式
D.低功耗模式

2.不是STM32的低功耗模式有( D )。(多选)
A.睡眠模式
B.停止模式
C.待机模式
D.运转模式

3.在停止模式下,如下哪些是正确的( ABC )。(多选)
A.1.8V供电区域的所有时钟都被停止
B.PLL、HIS 和HSE RC振荡器的功能将被禁止
C.SRAM和寄存器内容将被保留下来
D.SRAM和寄存器内容将被丢失

1.DMA控制器可编程的数据传输数目最大为( B )。
A.65536
B.65535
C.1024
D.4096

2.每个DMA通道具有( A )个事件标志。
A.3
B.4
C.5
D.6

3.DMA控制器中,独立的源和目标数据区的传输宽度为( ABCD )(多选)。
A.字节
B.半字
C.全字
D.以上都可以

4.STM32中,1 个DMA请求占用至少( B )个周期的CPU 访问系统总线时间。
A.1
B.2
C.3
D.4

1.在STM32中,备份寄存器是( A )的寄存器。
A.16 位
B.32 位
C.8 位
D.4 位

2.为了允许访问备份寄存器和RTC,电源控制寄存器(PWR_CR)的DBP 位必须置为( A )。
A.1
B.2
C.0
D.3

3.下列哪个不是备份寄存器( C )。
A.BKP_DR1
B.BKP_DR3
C.BKP_RTCCR
D.BKP_DR5

1.若看门狗WWDG被启动,当递减计数器的值小于( A ),则产生复位。
A.0x40
B.0x70
C.0x4F
D.0x7F
2.在寄存器IWDG_KR中写入( A ),开始启用独立看门狗。
A.0xCCCC
B.0xBBBB
C.0xAAAA
D.0xDDDD

3.如果窗口看门狗启动,并且当7 位(T[6:0])递减计数器 ( A )时,则产生一个复位动作。
A.从0x40翻转到0x3F
B.从0x50翻转到0x4F
C.从0x60翻转到0x5F
D.从0x70翻转到0x6F

1.STM32的可编程TIM1定时器的时基单元包含( ABCD )。(多选)
A.计数器寄存器(TIM1_CNT)
B.预分频器寄存器 (TIM1_PSC)
C.自动装载寄存器 (TIM1_ARR)
D.周期计数寄存器 (TIM1_RCR)

2.高级定时器TIM1的特性( ABCD )。(多选)
A.具备16位上,下,上/下自动装载计数器
B.具备16位可编程预分频器。
C.可以在指定数目的计数器周期之后更新定时器寄存器。
D.可以通过事件产生中断,中断类型丰富,具备DMA功能。

3.定时器TIM1的特殊工作模式包括( ABCD )。(多选)
A.输入捕获模式
B.PWM 输入模式
C.编码器接口模式
D.单脉冲模式(OPM)

1.通用定时器TIMx的特性( ABCD )。(多选)
A.具备16位向上,向下,向上/向下自动装载计数器。
B.具备16位可编程预分频器。
C.具备4个独立通道。
D.可以通过事件产生中断,中断类型丰富,具备DMA功能。

2.通用定时器TIMx的特殊工作模式包括( ABCD )。(多选)
A.输入捕获模式
B.PWM 输入模式
C.输出模式
D.单脉冲模式(OPM)

3.STM32的可编程通用定时器的时基单元包含( ABC )。(多选)
A.计数器寄存器(TIMx_CNT)
B.预分频器寄存器(TIMx_PSC)
C.自动装载寄存器(TIMx_ARR)
D.以上都不是

1.ARM Cortex-M3不可以通过( D )唤醒CPU。
A.I/O端口
B.RTC 闹钟
C.USB唤醒事件
D.PLL

2.STM32嵌套向量中断控制器(NVIC) 具有( A ) 个可编程的优先等级。
A.16
B.43
C.72
D.36

3.STM32的外部中断/事件控制器(EXTI)支持( C )个中断/事件请求。
A.16
B.43
C.19
D.36

1.哪些是STM32的ADC系统的特点(多选)( ABCD )。
A.12-位分辨率
B.自校准
C.可编程数据对齐
D.单次和连续转换模式

2.在ADC的扫描模式中,如果设置了DMA位,在每次EOC后,DMA控制器把规则组通道的转换数据传输到( A )中。
A.SRAM
B.Flash
C.ADC_JDRx寄存器
D.ADC_CR1

3.STM32规则组由多达( A )个转换组成。
A.16
B.18
C.4
D.20

4.在STM32中,( A )寄存器的ALIGN位选择转换后数据储存的对齐方式。
A.ADC_CR2
B.ADC_JDRx
C.ADC_CR1
D.ADC_JSQR

1.STM32的Flash闪存编程一次可以写入( A )位。
A.16
B.8
C.32
D.4

2.STM32主存储块的页大小为( A ) 字节。
A.1K
B.3K
C.2K
D.4K

3.用户选择字节的大小为( A )。
A.512字节
B.2K
C.1K
D.128K

4.下列哪些不是STM32闪存存储器的特点( C )。
A.大容量
B.高速
C.掉电不保存
D.具有选择字节加载器

1.在APB2上的I/O脚的翻转速度为( A )。
A.18MHz
B.50MHz
C.36MHz
D.72MHz

2.定时器2的TIM2_REMAP[1:0]为“10”和“11”的重映射,适用于( AB )封装的芯片。
A.64引脚
B.100引脚
C.36引脚
D.144引脚

3.USART2的USART2_REMAP = 1的重映射只适用于( B )引脚的封装。
A.64引脚
B.100引脚
C.36引脚
D.144引脚

4.当输出模式位MODE[1:0]=“10”时,最大输出速度为( B )。
A.10MHz
B.2MHz
C.50MHz
D.72MHz

1.下列哪个不是RealView MDK开发环境的特点( D )。
A.Windows风格
B.兼容的Keil μVision界面
C.全面的ARM处理器支持
D.体积庞大

4.下列哪种方法可以对STM32进行程序下载( ABCD )。(多选)
A.Keil ULink
B.J-Link
C.在应用编程
D.以上都可以

1.在APB2上的I/O脚的翻转速度为( A )。
A.18MHz
B.50MHz
C.36MHz
D.72MHz

4.当输出模式位MODE[1:0]=“10”时,最大输出速度为( B )。
A.10MHz
B.2MHz
C.50MHz
D.72MHz

1.STM32的Flash闪存编程一次可以写入( A )位。
A.16
B.8
C.32
D.4

2.STM32主存储块的页大小为( A ) 字节。
A.1K
B.3K
C.2K
D.4K

3.用户选择字节的大小为( A )。
A.512字节
B.2K
C.1K
D.128K

4.下列哪些不是STM32闪存存储器的特点( C )。
A.大容量
B.高速
C.掉电不保存
D.具有选择字节加载器

1.哪些是STM32的ADC系统的特点(多选)( ABCD )。
A.12-位分辨率
B.自校准
C.可编程数据对齐
D.单次和连续转换模式

2.在ADC的扫描模式中,如果设置了DMA位,在每次EOC后,DMA控制器把规则组通道的转换数据传输到( A )中。
A.SRAM
B.Flash
C.ADC_JDRx寄存器
D.ADC_CR1

3.STM32规则组由多达( A )个转换组成。
A.16
B.18
C.4
D.20

4.在STM32中,( A )寄存器的ALIGN位选择转换后数据储存的对齐方式。
A.ADC_CR2
B.ADC_JDRx
C.ADC_CR1
D.ADC_JSQR

1.ARM Cortex-M3不可以通过( D )唤醒CPU。
A.I/O端口
B.RTC 闹钟
C.USB唤醒事件
D.PLL

2.STM32嵌套向量中断控制器(NVIC) 具有( A ) 个可编程的优先等级。
A.16
B.43
C.72
D.36

3.STM32的外部中断/事件控制器(EXTI)支持( C )个中断/事件请求。
A.16
B.43
C.19
D.36

1.STM32的USART根据( A )寄存器M位的状态,来选择发送8位或者9位的数据字。
A.USART_CR1
B.USART_CR2
C.USART_BRR
D.USART_CR3

2.STM32的bxCAN的主要工作模式为( ABD )。
A.初始化模式
B.正常模式
C.环回模式
D.睡眠模式

3.在程序中,可以将CAN_BTR寄存器的( AB )位同时置1,来进入环回静默模式。(多选)
A.LBKM
B.SILM
C.BTR
D.以上都不是

1.通用定时器TIMx的特性( ABCD )。(多选)
A.具备16位向上,向下,向上/向下自动装载计数器。
B.具备16位可编程预分频器。
C.具备4个独立通道。
D.可以通过事件产生中断,中断类型丰富,具备DMA功能。

2.通用定时器TIMx的特殊工作模式包括( ABCD )。(多选)
A.输入捕获模式
B.PWM 输入模式
C.输出模式
D.单脉冲模式(OPM)

3.STM32的可编程通用定时器的时基单元包含( ABC )。(多选)
A.计数器寄存器(TIMx_CNT)
B.预分频器寄存器(TIMx_PSC)
C.自动装载寄存器(TIMx_ARR)
D.以上都不是

1.STM32的可编程TIM1定时器的时基单元包含( ABCD )。(多选)
A.计数器寄存器(TIM1_CNT)
B.预分频器寄存器 (TIM1_PSC)
C.自动装载寄存器 (TIM1_ARR)
D.周期计数寄存器 (TIM1_RCR)

2.高级定时器TIM1的特性( ABCD )。(多选)
A.具备16位上,下,上/下自动装载计数器
B.具备16位可编程预分频器。
C.可以在指定数目的计数器周期之后更新定时器寄存器。
D.可以通过事件产生中断,中断类型丰富,具备DMA功能。

3.定时器TIM1的特殊工作模式包括( ABCD )。(多选)
A.输入捕获模式
B.PWM 输入模式
C.编码器接口模式
D.单脉冲模式(OPM)

1.STM32提供了三种不同的时钟源,其都可被用来驱动系统时钟SYSCLK,这三种时钟源分别为( ABC )。
A.HSI振荡器时钟
B.HSE振荡器时钟
C.PLL时钟
D.HLI振荡时钟

2.在STM32中,当( AB )发生时,将产生电源复位。(多选)
A.从待机模式中返回
B.上电/掉电复位(POR/PDR复位)
C.NRST管脚上的低电平
D.PLL

3.以下哪个时钟信号可被选作MCO 时钟( ABCD )。(多选)
A.SYSCLK
B.HSI
C.HSE
D.以2分频的PLL 时钟

1.在STM32中,备份寄存器是( A )的寄存器。
A.16 位
B.32 位
C.8 位
D.4 位

2.为了允许访问备份寄存器和RTC,电源控制寄存器(PWR_CR)的DBP 位必须置为( A )。
A.1
B.2
C.0
D.3

3.下列哪个不是备份寄存器( C )。
A.BKP_DR1
B.BKP_DR3
C.BKP_RTCCR
D.BKP_DR5

1.DMA控制器可编程的数据传输数目最大为( A )。
A.65536
B.65535
C.1024
D.4096

2.每个DMA通道具有( A )个事件标志。
A.3
B.4
C.5
D.6

3.DMA控制器中,独立的源和目标数据区的传输宽度为( ABCD )(多选)。
A.字节
B.半字
C.全字
D.以上都可以

4.STM32中,1 个DMA请求占用至少( B )个周期的CPU 访问系统总线时间。
A.1
B.2
C.3
D.4

祝愿各位不留遗憾,加油

你可能感兴趣的:(嵌入式,蓝桥杯嵌入式,stm32,电子,蓝桥杯)