乐趣区

关于javascript:基于STM32f103C8T6的蓝牙遥控小车制造

第 0 章:前言

  • 此次智能小车设计是从 0 开始设计波及多个模块
  • 此文章中不仅蕴含制作过程,也蕴含制作过程中遇到的一些问题及解决办法。
  • 如果不设置时钟的话,零碎默认时钟是 72MHz,在 system_stm32f10x.c 文件中有定义(#define SYSCLK_FREQ_72MHz 72000000)

第一章:让小车动起来

波及知识点及模块

  • 波及模块:二路 BTN 驱动模块、LM317 可调稳压模块
  • PWM 调速:给电机正负极通电能够间接使电机转动起来,然而管制电机转动速度就须要到 PWM 了。当设置通电的占空比越小(通电工夫与一个周期的比值),电机体现出的景象就是转速升高。
  • 正反转:将电机上两接线反接即可。
  • 预分频值 Precaler = 主频÷时钟频率 -1(分频后的频率);72000000÷10000=7200-1
  • 计数周期 Period = 时钟频率÷指标频率 -1
  • PWM 初始化程序如下:这里应用的是 TIM2 的通道 3 作为 pwm 输入(PA2 接 A1,PA3 接 A2)
  • A1/A2/B1/B2 是指驱动模块上的接口。

试验代码

void pwm_init_left(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;   // 申明一个构造体变量,用来初始化 GPIO

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;// 申明一个构造体变量,用来初始化定时器

    TIM_OCInitTypeDef TIM_OCInitStructure;// 依据 TIM_OCInitStruct 中指定的参数初始化外设 TIMx

    /* 开启时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

    /*  配置 GPIO 的模式和 IO 口 PA2*/
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;// 复用推挽输入
    GPIO_Init(GPIOA,&GPIO_InitStructure);        



    // T = CNT/fHz = 9000/72000000s
    // Period = 时钟频率÷指标频率 -1
    // 预分频值:Precaler = 主频÷指标频率 -1(分频后的频率);72000000÷10000=7200-1
    //TIM2 定时器初始化
    TIM_TimeBaseInitStructure.TIM_Period = 99;       // 周期,不分频, 设置主动重装载寄存器周期的值
    TIM_TimeBaseInitStructure.TIM_Prescaler = 719;// 设置用来作为 TIMx 时钟频率预分频值(主频÷指标频率 -1)。TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;// 设置时钟宰割:
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;    //TIM 向上计数模式
    TIM_TimeBaseInit(TIM2, & TIM_TimeBaseInitStructure);

    // 将 TIM2 的输入引脚进行 fll remap 到 PA15,也就是 P3.7
    //GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);


    //PWM 初始化      // 依据 TIM_OCInitStruct 中指定的参数初始化外设 TIMx
    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//PWM 输入使能
    TIM_OCInitStructure.TIM_Pulse = 50;
    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);// 使能 TIMx 外设
}

遇到的问题

  1. 第一次应用 J_Link 须要装置 J_Link 的驱动,这个间接下载 < 驱动精灵 > 软件,它会自动检测短少的驱动,下载安装即可。
  2. 在应用 J_link 调试时留神要先下载一次程序后再用 J_link。我的是呈现这种状况,其他人的不晓得。(在一刚开始调试程序时,电机能转然而调不了速,就是因为这个状况)
  3. TIM_OCInitStructure.TIM_Pulse 的值不能设置过小,否则电机不会转动,设置为 40 时就不会转动(这里存在另一个问题,就是设置的值超过 50 之后,电机转速差不多,也就是无奈扭转速度)
  4. 还有一个问题就是这种办法无奈扭转电机正反转,因为这里只应用了一个通道。

问题解决方案

  1. 首先 TIM_Pulse 的值不能设置过小的问题:经检测是 TIM_Period 周期的值设置过小,频率太高,电机没有那么好的性能。能够将 TIM_Period 周期设置为 7200-1,频率为 10khz。
  2. 而后就是电机正反转的问题:能够利用同一个定时器的四个不同通道(OC1/2/3/4),别离接到 A1/A2/B1/B2 上,而后别离设置四个通道的比拟寄存器的值即可实现正反转(例如将 OC1 的比拟值设置为 5000,OC2 的比拟值设置为 0 即可正转;反之即可反转)
  3. 这里如果像下面那样写的话,四个通道要写很多代码,所以这里做了一点扭转。
  4. 这里设置比拟寄存器中的值使用到了库函数中的 TIM_SetCompare_x 函数。
  5. 
    /**
      * @brief  Sets the TIMx Capture Compare1 Register value
      * @param  TIMx: where x can be 1 to 17 except 6 and 7 to select the TIM peripheral.
      * @param  Compare1: specifies the Capture Compare1 register new value.
      * @retval None
      */
    void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1)
    {
      /* Check the parameters */
      assert_param(IS_TIM_LIST8_PERIPH(TIMx));
      /* Set the Capture Compare1 Register value */
      TIMx->CCR1 = Compare1;
    }
    

解决方案代码


//PA0-4,用于 PWM 输入
void PWM_TIM_2_Init(u16 Period,u16 Prescaler)
{
    GPIO_InitTypeDef GPIO_InitStructure;   // 申明一个构造体变量,用来初始化 GPIO
    
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;// 申明一个构造体变量,用来初始化定时器

    TIM_OCInitTypeDef TIM_OCInitStructure;// 依据 TIM_OCInitStruct 中指定的参数初始化外设 TIMx

    /* 开启时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

    /*  配置 GPIO 的模式和 IO 口 PA0 1 2 3*/
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;// 复用推挽输入
    GPIO_Init(GPIOA,&GPIO_InitStructure);        

    // T = CNT/fHz = 9000/72000000s
    // Period = 时钟频率÷指标频率 -1
    // 预分频值:Precaler = 主频÷时钟频率 -1(分频后的频率);72000000÷10000=720-1
    //TIM3 定时器初始化
    TIM_TimeBaseInitStructure.TIM_Period = Period;       // 周期,不分频, 设置主动重装载寄存器周期的值
    TIM_TimeBaseInitStructure.TIM_Prescaler = Prescaler;// 设置用来作为 TIMx 时钟频率预分频值(主频÷目标频率 -1)TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;// 设置时钟宰割:
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;    //TIM 向上计数模式
    TIM_TimeBaseInit(TIM2, & TIM_TimeBaseInitStructure);

    // 将 TIM2 的输入引脚进行 fll remap 到 PA15,也就是 P3.7
    //GPIO_PinRemapConfig(GPIO_FullRemap_TIM2, ENABLE);


    //PWM 初始化      // 依据 TIM_OCInitStruct 中指定的参数初始化外设 TIMx
    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//PWM 输入使能
    TIM_OCInitStructure.TIM_Pulse = 0;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    
    TIM_OC1Init(TIM2,&TIM_OCInitStructure);
    TIM_OC2Init(TIM2,&TIM_OCInitStructure);
    TIM_OC3Init(TIM2,&TIM_OCInitStructure);
    TIM_OC4Init(TIM2,&TIM_OCInitStructure);
    
    TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable);
    
    TIM_ARRPreloadConfig(TIM2,ENABLE);    //TIM2 在 ARR 上预装载寄存器使能    
    TIM_Cmd(TIM2,ENABLE);                                // 使能 TIMx 外设
}



int main(void)
{PWM_TIM_2_Init(7199,0);
    
    // 正转
    TIM_SetCompare1(TIM2,5000);
    TIM_SetCompare2(TIM2,0);
    // 反转
    TIM_SetCompare3(TIM2,0);
    TIM_SetCompare4(TIM2,3000);
    
    while(1)
    {}}

第二章:测量小车转速(编码器)

光电编码器

电机接线图:

  • 光电编码器输入的是正弦波,A 相和 B 相都是输入正弦波。
  • 当 A 相为回升沿时,B 相若为低电平,电机正转。
  • 当 A 相为回升沿时,B 相若为高电平,电机反转。
  • 留神:因为我这里只捕捉 A 相的回升沿,所以 AB 相的线不能接反了,否则 TIM3 的通道 1 的中断触发不了。

输出捕捉

  • 性能:用于测量输出信号的脉宽、测量 PWM 输出信号的频率及占空比。
  • 实现流程:

    • 首先配置某个定时器为计数器模式(计数器的频率必须远大于输出的频率)
    • 而后再配置该定时器的一个通道作为捕捉通道(配置为回升沿检测或降落沿检测)
    • 当这个通道检测到对应的边际时,就会触发该通道的中断(此时计数器的值会主动加载到捕捉比拟寄存器中)
    • 输出波形的周期 = 相邻两个捕捉寄存器值之差 * 计数器的周期值。

试验代码



u8 i = 0;                                 // 标记第一次还是第二次检测到回升沿
u16 BianMaQi_speed_ZUO = 0;  // 编码器的输入 1 个周期时,定时器的计数值
u16 BianMaQi_speed_YOU = 0;
u8 zhen_fan_zhuan_ZUO = 0;   // 标记电机正转还是反转(1 正 0 反)u8 zhen_fan_zhuan_YOU = 0;
u16    zhuan_su_ZUO = 0;                 // 小车转速 r /min
u16    zhuan_su_YOU = 0;    
double BianMaQi_ZUO_zhouqi = 0.0;// 编码器的周期
double BianMaQi_YOU_zhouqi = 0.0;

/*******************************************************************************
* 函 数 名         : TIM3_CH1_Input_Init(应用 TIM3 的 通道 1 PA6 接左轮 A 相 和 通道 2 PA7 接左轮 B 相)*    函数参数:arr:主动重装载值;psc:预分频系数
*    函数返回值:无
* 函数性能             : TIM3_CH1 输出捕捉初始化函数(只捕捉通道 1 的波形)*******************************************************************************/
void TIM3_CH1_Input_Init(u16 Period,u16 Prescaler)    
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);// 使能 TIM3 时钟
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;// 管脚设置
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;     // 设置上拉输出模式
    GPIO_Init(GPIOA,&GPIO_InitStructure);        /* 初始化 GPIO */
    
    TIM_TimeBaseInitStructure.TIM_Period=Period;   // 主动装载值
    TIM_TimeBaseInitStructure.TIM_Prescaler=Prescaler; // 分频系数
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; // 设置向上计数模式
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);    
    
    TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; // 通道 1
    TIM_ICInitStructure.TIM_ICFilter=0x00;  // 无滤波
    TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;// 捕捉极性
    TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; // 分频系数
    TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;// 间接映射到 TI1
    TIM_ICInit(TIM3,&TIM_ICInitStructure);
    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
    TIM_ITConfig(TIM3,TIM_IT_CC1,ENABLE);
    
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;// 中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;        // 子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ 通道使能
    NVIC_Init(&NVIC_InitStructure);
        
    TIM_Cmd(TIM3,ENABLE); // 使能定时器
}




/*******************************************************************************
* 函 数 名         : TIM3_IRQHandler
*    函数参数:无
*    函数返回值:无
* 函数性能             : TIM3 中断函数(读取 TIM3 计数器的值, 并检测电机是正转还是反转)*******************************************************************************/
void TIM3_IRQHandler(void)
{if(TIM_GetITStatus(TIM3,TIM_IT_CC1) == 1)          // 检测 TIM3 的通道 1 是否产生中断
    {if(TIM_GetFlagStatus(TIM3,TIM_FLAG_CC1))
        {BianMaQi_speed_ZUO = TIM_GetCounter(TIM3) - BianMaQi_speed_ZUO;    
            BianMaQi_ZUO_zhouqi = BianMaQi_speed_ZUO * 1/1000000;                // 计算编码器的周期
            zhuan_su_ZUO = BianMaQi_ZUO_zhouqi * 500;                                        // 小车转速 r /min
            i++;      

        }
        if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7) == 0)        // A 相为回升沿,B 相为 0,正转
        {zhen_fan_zhuan_ZUO = 1;}
        else
        {zhen_fan_zhuan_ZUO = 0;}
        if(i==2)
        {TIM_SetCounter(TIM3,0);     // 定时器 3 的计数器清零
            TIM_Cmd(TIM3,ENABLE);            // 使能定时器 3
            BianMaQi_speed_ZUO = 0;
            i = 0;
        }

        TIM_ClearITPendingBit(TIM3,TIM_IT_CC1|TIM_IT_Update);        // 革除 TIMx 的中断挂起位
    }

}




/*******************************************************************************
* 函 数 名             : TIM4_CH3_Input_Init(应用 TIM4 的 通道 3 PB8 接右轮 A 相 和 通道 2 PB9 接右轮 B 相)* 函数参数:arr:主动重装载值;psc:预分频系数
* 函数返回值:无
* 函数性能          : TIM4_CH3 输出捕捉初始化函数(只捕捉通道 3 的波形)*******************************************************************************/
void TIM4_CH3_Input_Init(u16 Period,u16 Prescaler)    
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);// 使能 TIM4 时钟
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9;// 管脚设置
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;     // 设置上拉输出模式
    GPIO_Init(GPIOB,&GPIO_InitStructure);        /* 初始化 GPIO */
    
    TIM_TimeBaseInitStructure.TIM_Period=Period;   // 主动装载值
    TIM_TimeBaseInitStructure.TIM_Prescaler=Prescaler; // 分频系数
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; // 设置向上计数模式
    TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);    
    
    TIM_ICInitStructure.TIM_Channel=TIM_Channel_3; // 通道 1
    TIM_ICInitStructure.TIM_ICFilter=0x00;  // 无滤波
    TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;// 捕捉极性
    TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; // 分频系数
    TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;// 间接映射到 TI1
    TIM_ICInit(TIM4,&TIM_ICInitStructure);
    TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
    TIM_ITConfig(TIM4,TIM_IT_CC3,ENABLE);
    
    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;// 中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;        // 子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ 通道使能
    NVIC_Init(&NVIC_InitStructure);
        
    TIM_Cmd(TIM4,ENABLE); // 使能定时器
}




/*******************************************************************************
* 函 数 名         : TIM4_IRQHandler
* 函数参数:无
* 函数返回值:无
* 函数性能:: TIM4 中断函数(读取 TIM4 计数器的值, 并检测电机是正转还是反转)*******************************************************************************/
void TIM4_IRQHandler(void)
{if(TIM_GetITStatus(TIM4,TIM_IT_CC3) == 1)          // 检测 TIM3 的通道 1 是否产生中断
    {if(TIM_GetFlagStatus(TIM4,TIM_FLAG_CC3))
        {BianMaQi_speed_YOU = TIM_GetCounter(TIM4) - BianMaQi_speed_YOU;    
            BianMaQi_YOU_zhouqi = BianMaQi_speed_YOU * 1/1000000;                // 计算编码器的周期
            zhuan_su_YOU = BianMaQi_YOU_zhouqi * 500;                                        // 小车转速 r /min
            i++;      

        }
        if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9) == 0)        // A 相为回升沿,B 相为 0,正转
        {zhen_fan_zhuan_YOU = 1;}
        else
        {zhen_fan_zhuan_YOU = 0;}
        if(i==2)
        {TIM_SetCounter(TIM4,0);     // 定时器 3 的计数器清零
            TIM_Cmd(TIM4,ENABLE);            // 使能定时器 3
            BianMaQi_speed_YOU = 0;
            i = 0;
        }

        TIM_ClearITPendingBit(TIM4,TIM_IT_CC3|TIM_IT_Update);        // 革除 TIMx 的中断挂起位
    }

}


遇到的问题

在 mian 函数中援用两个输出捕捉初始化函数后(TIM3_CH1_Input_Init 和 TIM4_CH3_Input_Init),再援用设置比拟寄存器函数 TIM_SetCompare1 时,电机不转动。通过测试是输出捕捉初始化函数有问题(在此函数之前应用 TIM_SetCompare1 时,电机可能转动)

  • 代码示例
  • int main(void)
    {NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 中断优先级分组 分 2 组
    
      PWM_TIM_2_Init(7199,0);
      
      TIM3_CH1_Input_Init(0xffff,0);            
      TIM4_CH3_Input_Init(0xffff,0);
    
      TIM_SetCompare1(TIM2,0);
      TIM_SetCompare2(TIM2,5000);
      TIM_SetCompare3(TIM2,0);
      TIM_SetCompare4(TIM2,5000);
      while(1)
      {}}

解决方案

  • 将 TIM3_CH1_Input_Init 函数中的中断嵌套 NVIC 设置敞开即可。
/*******************************************************************************
* 函 数 名         : TIM3_CH1_Input_Init(应用 TIM3 的 通道 1 PA6 接左轮 A 相 和 通道 2 PA7 接左轮 B 相)*    函数参数:arr:主动重装载值;psc:预分频系数
*    函数返回值:无
* 函数性能             : TIM3_CH1 输出捕捉初始化函数(只捕捉通道 1 的波形)*******************************************************************************/
void TIM3_CH1_Input_Init(u16 Period,u16 Prescaler)    
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    //NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);// 使能 TIM3 时钟
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;// 管脚设置
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;     // 设置上拉输出模式
    GPIO_Init(GPIOA,&GPIO_InitStructure);        /* 初始化 GPIO */
    
    TIM_TimeBaseInitStructure.TIM_Period=Period;   // 主动装载值
    TIM_TimeBaseInitStructure.TIM_Prescaler=Prescaler; // 分频系数
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; // 设置向上计数模式
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);    
    
    TIM_ICInitStructure.TIM_Channel=TIM_Channel_1; // 通道 1
    TIM_ICInitStructure.TIM_ICFilter=0x00;  // 无滤波
    TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;// 捕捉极性
    TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; // 分频系数
    TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;// 间接映射到 TI1
    TIM_ICInit(TIM3,&TIM_ICInitStructure);
    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);        
    TIM_ITConfig(TIM3,TIM_IT_CC1,ENABLE);
    
    //NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;// 中断通道
    //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
    //NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;        // 子优先级
    //NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ 通道使能
    //NVIC_Init(&NVIC_InitStructure);
        
    TIM_Cmd(TIM3,ENABLE); // 使能定时器
}

第三章:蓝牙模块的退出

  • 配置 USART 串口,用单片机的 USART1_TX 连贯 RXD,USART1_RX 连贯 TXD。
  • 留神:蓝牙的波特率必须与串口的雷同。
  • 对于串口的相干问题看另一篇文章:https://segmentfault.com/a/11…

遇到的问题及解决办法

  • 问题:在配置完串口后,手机连贯蓝牙,后果呈现乱码(这应该都是串口的常出问题了吧)
  • 问题所在:波特率不匹配。
  • 解决办法:进过检测,蓝牙模块的默认波特率是 9600,尽管在设置串口波特率时我曾经设置为 9600 了,然而任然呈现乱码。起因是库默认应用 8MHz 晶振,能够通过宏应用 25MHz 或 12M 晶振;具体定义在 stm32f10x.h 文件中,HSE_VALUE 一开始定义成了 8000000,改成 12000000 搞定,串口通信就能够显示失常。

代码示例

#include "usart.h"         


unsigned char Data;

/*******************************************************************************
* 函 数 名         : USART1_Init
* 函数性能           : USART1 初始化函数
* 输    入         : bound: 波特率
* 输    出         : 无
*******************************************************************************/ 
void USART1_Init(u32 bound)
{
   //GPIO 端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);     // 关上时钟
 
    
    /*  配置 GPIO 的模式和 IO 口 */
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX               // 串口输入 PA9
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;        // 复用推挽输入
    GPIO_Init(GPIOA,&GPIO_InitStructure);  /* 初始化串口输出 IO */
    
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX             // 串口输出 PA10
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;          // 模仿输出
    GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化 GPIO */
    
    //Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;// 串口 1 中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;// 抢占优先级 3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;        // 子优先级 3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ 通道使能
    NVIC_Init(&NVIC_InitStructure);    // 依据指定的参数初始化 VIC 寄存器、//USART1 初始化设置
    USART_InitStructure.USART_BaudRate = bound;// 波特率设置
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;// 字长为 8 位数据格式
    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(USART1, &USART_InitStructure); // 初始化串口 1
    
    USART_Cmd(USART1, ENABLE);  // 使能串口 1 
    
    USART_ClearFlag(USART1, USART_FLAG_TC);
        
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);// 开启相干中断

    
}

/*******************************************************************************
* 函 数 名         : USART1_IRQHandler
* 函数性能           : USART1 中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/ 
void USART1_IRQHandler(void)                    // 串口 1 中断服务程序
{if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  // 接管中断
    {Data = USART_ReceiveData(USART1);//(USART1->DR);    // 读取接管到的数据
    USART_SendData(USART1,Data);
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
    } 
    USART_ClearFlag(USART1,USART_FLAG_TC);
    USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}     

 

退出移动版