[STM32F1] stm32(F103c8t6)自学笔记

[复制链接]
5051|177
 楼主| t60yz 发表于 2023-11-22 11:42 | 显示全部楼层
 楼主| t60yz 发表于 2023-11-22 11:42 | 显示全部楼层
 楼主| t60yz 发表于 2023-11-22 11:43 | 显示全部楼层
 楼主| t60yz 发表于 2023-11-22 11:43 | 显示全部楼层
4.3 代码配置
4.3.1(呼吸灯、重映射)
先和配置定时器步骤差不多,只不过最后不需要配置中断和NVIC,就直接配置CCR

CCR需要先使用TIM_OCStructInit()整体初始化,然后再单独配置需要的模式:

    TIM_OCInitTypeDef TIM_OCInitStruct;
    TIM_OCStructInit(&TIM_OCInitStruct);//先整体初始化,防止有些变量未初始化而出错
    TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置为PWM1输出模式
    TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF为高极性
    TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置输出使能
    TIM_OCInitStruct.TIM_Pulse=100;//配置CCR计数器值
    TIM_OC1Init(TIM2,&TIM_OCInitStruct);

重映射使用看视频学习
 楼主| t60yz 发表于 2023-11-22 11:43 | 显示全部楼层
  1. #include "stm32f10x.h"                  // Device header
  2. #include "OLED.h"
  3. #include "PWM.h"
  4. /***************************************************/PWM模块
  5. #include "stm32f10x.h"                  // Device header
  6. #include "Delay.h"


  7. void pwm_init(void)
  8. {
  9.         //**1.打开总的RCC,要配置GPIO从而传入外部时钟
  10.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
  11.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  12.         //**2.配置PWM输出引脚
  13.         GPIO_InitTypeDef GPIO_InitStruct;
  14.        
  15.         GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
  16.         GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
  17.         GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
  18.         GPIO_Init(GPIOA,&GPIO_InitStruct);
  19.        
  20.         //**3.配置时基单元
  21.         //配置为1000KHz,分辨率为1%
  22.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
  23.        
  24.         TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
  25.         TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
  26.         TIM_TimeBaseInitStruct.TIM_Period=100-1;//设置预装载值       //外部时钟的话用不了这么高的频率
  27.         TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//设置预分频值
  28.         TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
  29.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
  30.         TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

  31.         //**4.配置CCR
  32.         TIM_OCInitTypeDef TIM_OCInitStruct;
  33.         TIM_OCStructInit(&TIM_OCInitStruct);//先整体初始化,防止有些变量未初始化而出错
  34.         TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置为PWM1输出模式
  35.         TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF为高极性
  36.         TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置输出使能
  37.         TIM_OCInitStruct.TIM_Pulse=100;//配置CCR计数器值
  38.         TIM_OC1Init(TIM2,&TIM_OCInitStruct);
  39.        
  40.         //5.开始计数
  41.         TIM_Cmd(TIM2,ENABLE);
  42. }

  43. void LED_run(void)
  44. {
  45.         uint16_t num;
  46.         for(num=100;num>0;num--)
  47.         {
  48.                 TIM_SetCompare1(TIM2,num);
  49.                 Delay_ms(10);

  50.         }
  51.         for(num=0;num<100;num++)
  52.         {
  53.                 TIM_SetCompare1(TIM2,num);
  54.                 Delay_ms(10);
  55.         }
  56. }

  57. /***************************************************/主函数

  58. int main(void)
  59. {
  60.         OLED_Init();
  61.         pwm_init();
  62.         OLED_ShowString(1,1,"Hello,my honey");
  63. //        OLED_ShowString(2,1,"Hello WangFang");
  64. //        OLED_ShowString(3,1,"Hello Tomorrow");
  65. //        OLED_ShowString(4,1,"I miss you");
  66.         while(1)
  67.         {
  68.                 LED_run();
  69.         }
  70. }
 楼主| t60yz 发表于 2023-11-22 11:43 | 显示全部楼层
4.3.2(旋钮控制舵机角度PWM)
旋转旋钮触发中断从而改变CCR的值(改变占空比)

要注意舵机的信号周期为20ms,既50Hz
 楼主| t60yz 发表于 2023-11-22 11:43 | 显示全部楼层
  1. #include "stm32f10x.h"                  // Device header
  2. #include "OLED.h"
  3. #include "PWM.h"
  4. #include "mokuaicount.h"

  5. /***************************************************/PWM模块
  6. #include "stm32f10x.h"                  // Device header
  7. #include "PWM.h"
  8. #include "Delay.h"


  9. void pwm_init(void)
  10. {
  11.         //**1.打开总的RCC,要配置GPIO从而传入外部时钟
  12.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
  13.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  14.         //**2.配置PWM输出引脚PA0
  15.         GPIO_InitTypeDef GPIO_InitStruct;
  16.        
  17.         GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
  18.         GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
  19.         GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
  20.         GPIO_Init(GPIOA,&GPIO_InitStruct);
  21.        
  22.         //**3.配置时基单元
  23.         //配置为1000KHz,分辨率为1%
  24.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
  25.        
  26.         TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
  27.         TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
  28.         TIM_TimeBaseInitStruct.TIM_Period=20000-1;//设置预装载值       //外部时钟的话用不了这么高的频率
  29.         TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//设置预分频值
  30.         TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
  31.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
  32.         TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

  33.         //**4.配置CCR
  34.         TIM_OCInitTypeDef TIM_OCInitStruct;
  35.         TIM_OCStructInit(&TIM_OCInitStruct);
  36.         TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
  37.         TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
  38.         TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
  39.         TIM_OCInitStruct.TIM_Pulse=0;
  40.         TIM_OC1Init(TIM2,&TIM_OCInitStruct);
  41.        
  42.         //5.
  43.         //**6.开始计数
  44.         TIM_Cmd(TIM2,ENABLE);
  45. }

  46. void set_angle(uint16_t angle)
  47. {
  48.         TIM_SetCompare1(TIM2,angle);
  49. }

  50. /***************************************************/GPIO初始化
  51. #include "xuanniu.h"               
  52. #include "stm32f10x.h"

  53. void Xuanniu_init(uint16_t GPIO_Pin)//需要指定端口Pin进行模式设置
  54. {
  55.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE);//使能GPIOA的时钟
  56.        
  57.         GPIO_InitTypeDef Xuanniu_InitStruct;  

  58.         Xuanniu_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//设置为 上拉输入 模式
  59.         Xuanniu_InitStruct.GPIO_Pin=GPIO_Pin;  //外界参数设置Pin口
  60.         Xuanniu_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;  //输出速度为50MHz,在输入模式下该设置没用
  61.         GPIO_Init( GPIOB,&Xuanniu_InitStruct); //以上三个都要传入该函数初始化
  62. }

  63. /***************************************************/计数模块
  64. //**该模块由中断函数实现,可接入任意输入模式的模块实现计数
  65. //**这里引入Key实现数据的减法,LightR实现加法
  66. #include "stm32f10x.h"                  // Device header
  67. #include "mokuaicount.h"
  68. #include "Delay.h"
  69. #include "xuanniu.h"


  70. extern int num;

  71. void Count_interrupt_init(void)
  72. {
  73.         //1、2、**步骤一二在模块内已经实现
  74.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//AFIO时钟需要使能
  75.        
  76.         Xuanniu_init(GPIO_Pin_0|GPIO_Pin_1);
  77.         //3**配置AFIO,选择输入引脚PB1(C),PB0(A)
  78.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);//Xuanniu旋钮
  79.         GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
  80.         //4**配置EXTI寄存器,选择触发方式,这里配置EXTI和GPIO一样需要定义一个结构体
  81.         EXTI_InitTypeDef EXTI_InitStruct;
  82.         EXTI_InitStruct.EXTI_Line=EXTI_Line0|EXTI_Line1;
  83.         EXTI_InitStruct.EXTI_LineCmd=ENABLE;
  84.         EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
  85.         EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
  86.         EXTI_Init(&EXTI_InitStruct);
  87.         //5**配置NVIC,选择合适的中断优先级 --------每一个外设要单独配置
  88.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//要先分组,整个系统NVIC只分配一种模式
  89.         //**配置Xuanniu A端
  90.         NVIC_InitTypeDef NVIC_InitStruct_Xuanniu;
  91.         NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI0_IRQn;
  92.         NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
  93.         NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
  94.         NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
  95.         NVIC_Init(&NVIC_InitStruct_Xuanniu);
  96.         //**配置Xuanniu C端
  97.         NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI1_IRQn;
  98.         NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
  99.         NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
  100.         NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
  101.         NVIC_Init(&NVIC_InitStruct_Xuanniu);
  102.        
  103.        
  104.         //****所有配置完成
  105. }

  106. //中断位置随便放,也不需要声明
  107. void EXTI0_IRQHandler()//正转触发
  108. {
  109.         if(EXTI_GetITStatus(EXTI_Line0)==SET)
  110.         {
  111.                 if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0)
  112.                 {
  113.                         if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==1)
  114.                         {
  115.                                 num+=100;
  116.                         }
  117.                 }
  118.         }
  119.         EXTI_ClearITPendingBit(EXTI_Line0);
  120. }
  121. void EXTI1_IRQHandler()
  122. {
  123.         if(EXTI_GetITStatus(EXTI_Line1)==SET)
  124.         {
  125.                 if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)
  126.                 {
  127.                         if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==1)
  128.                         {
  129.                                 num-=100;
  130.                         }
  131.                 }
  132.         }
  133.         EXTI_ClearITPendingBit(EXTI_Line1);
  134. }


  135. /***************************************************/主函数
  136. int num=1500;

  137. int main(void)
  138. {
  139.         OLED_Init();
  140.         pwm_init();
  141.         Count_interrupt_init();
  142.         OLED_ShowString(1,1,"Hello,my baby");
  143.         set_angle(num);//默认居中
  144.         while(1)
  145.         {       
  146.                 if(num<=0)
  147.                 {
  148.                         num=0;
  149.                         OLED_ShowString(2,8,"Left Max ");
  150.                 }
  151.                 else if(num<1500)
  152.                 {
  153.                         OLED_ShowString(2,8,"Left     ");
  154.                 }
  155.                 else if(num==1500)
  156.                 {
  157.                         OLED_ShowString(2,8,"Midel    ");
  158.                 }
  159.                 else if(num<2500)
  160.                 {
  161.                         OLED_ShowString(2,8,"Right    ");
  162.                 }
  163.                 else if(num>=2500)
  164.                 {
  165.                         num=2500;
  166.                         OLED_ShowString(2,8,"Right Max");
  167.                 }
  168.                 OLED_ShowNum(2,1,num,5);
  169.                
  170.                 set_angle(num);
  171.         }
  172. }
 楼主| t60yz 发表于 2023-11-22 11:44 | 显示全部楼层
4.3.3 直流电机(调速)
stay待机控制直接接入高电平3.3v就可以了

in1、in2初始化GPIO(推完输出模式)然后设置高低电平即可
  1. #include "stm32f10x.h"                  // Device header
  2. #include "OLED.h"
  3. #include "Motor.h"

  4. /***************************************************/PWM模块
  5. #include "stm32f10x.h"                  // Device header
  6. #include "PWM.h"
  7. #include "Delay.h"


  8. void pwm_init(void)
  9. {
  10.         //**1.打开总的RCC,要配置GPIO从而传入外部时钟
  11.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  13.         //**2.配置PWM输出引脚PA0
  14.         GPIO_InitTypeDef GPIO_InitStruct;
  15.        
  16.         GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
  17.         GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
  18.         GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
  19.         GPIO_Init(GPIOA,&GPIO_InitStruct);
  20.        
  21.         //**3.配置时基单元
  22.         //配置为1000KHz,分辨率为1%
  23.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
  24.        
  25.         TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
  26.         TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
  27.         TIM_TimeBaseInitStruct.TIM_Period=100-1;//设置预装载值       //外部时钟的话用不了这么高的频率
  28.         TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//设置预分频值
  29.         TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
  30.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
  31.         TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

  32.         //**4.配置CCR
  33.         TIM_OCInitTypeDef TIM_OCInitStruct;
  34.         TIM_OCStructInit(&TIM_OCInitStruct);
  35.         TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
  36.         TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
  37.         TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
  38.         TIM_OCInitStruct.TIM_Pulse=0;
  39.         TIM_OC1Init(TIM2,&TIM_OCInitStruct);
  40.        
  41.         //5.开始计数
  42.         TIM_Cmd(TIM2,ENABLE);
  43. }

  44. void set_num(uint16_t num)
  45. {
  46.         TIM_SetCompare1(TIM2,num);
  47. }

  48. /***************************************************/电机模块
  49. #include "stm32f10x.h"                  // Device header
  50. #include "Motor.h"
  51. #include "PWM.h"

  52. void Motor_init(void)
  53. {
  54.         pwm_init();
  55.        
  56.         GPIO_InitTypeDef GPIO_InitStruct;//初始化两个方向控制引脚:PA4,PA5
  57.         GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
  58.         GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;
  59.         GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
  60.         GPIO_Init(GPIOA,&GPIO_InitStruct);
  61.         GPIO_Init(GPIOA,&GPIO_InitStruct);
  62. }

  63. void set_speed(int speed)
  64. {
  65.         if(speed>=0)
  66.         {
  67.                 set_num(speed);
  68.                 GPIO_SetBits(GPIOA,GPIO_Pin_4);
  69.                 GPIO_ResetBits(GPIOA,GPIO_Pin_5);
  70.         }
  71.         else
  72.         {
  73.                 set_num(-speed);
  74.                 GPIO_SetBits(GPIOA,GPIO_Pin_5);
  75.                 GPIO_ResetBits(GPIOA,GPIO_Pin_4);
  76.         }
  77. }

  78. /***************************************************/主函数


  79. int main(void)
  80. {
  81.         OLED_Init();
  82.         Motor_init();
  83.         while(1)
  84.         {       
  85.                 set_speed(-100);
  86.         }
  87. }
 楼主| t60yz 发表于 2023-11-22 11:44 | 显示全部楼层
5.TIM输入捕获
5.1 结构原理
利用定时器模块计数,当输入捕获模块的边沿检测模块检测到下降沿或上升沿,触发获取CNT的值,每记完一次后CNT清零,获取到的该周期的CNT值再通过与CNT计数频率即可得到该电平变化周期的时间T。
64647655d79109c1df.png
由此可见,测频法适合测量高频,测周法适合测量低频
 楼主| t60yz 发表于 2023-11-22 11:44 | 显示全部楼层
 楼主| t60yz 发表于 2023-11-22 11:44 | 显示全部楼层
 楼主| t60yz 发表于 2023-11-22 11:44 | 显示全部楼层
 楼主| t60yz 发表于 2023-11-22 11:44 | 显示全部楼层
 楼主| t60yz 发表于 2023-11-22 11:45 | 显示全部楼层
 楼主| t60yz 发表于 2023-11-22 11:45 | 显示全部楼层
5.2 代码配置
5.2.1 单通道测频率
这里采用TIM2产生PWM信号用于测量

配置TIM3时,也需要配置定时器时基模块使CNT计数,然后配置IC模块(通过一个结构体),再配置从模式的触发源和触发事件,使能定时器即可。

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "PWM.h"
#include "IC.h"

/***************************************************/PWM模块
#include "stm32f10x.h"                  // Device header


void pwm_init(void)
{
        //**1.打开总的RCC,要配置GPIO从而传入外部时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        //**2.配置PWM输出引脚
        GPIO_InitTypeDef GPIO_InitStruct;
       
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
       
        //**3.配置时基单元
        //配置为1000KHz,分辨率为1%
        TIM_InternalClockConfig(TIM2);//选择内部时钟源
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
       
        TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
        TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
        TIM_TimeBaseInitStruct.TIM_Period=100-1;//设置预装载值       //外部时钟的话用不了这么高的频率
        TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//设置预分频值
        TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
        TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

        //**4.配置CCR
        TIM_OCInitTypeDef TIM_OCInitStruct;
       
        TIM_OCStructInit(&TIM_OCInitStruct);//先整体初始化,防止有些变量未初始化而出错
        TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置为PWM1输出模式
        TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF为高极性
        TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置输出使能
        TIM_OCInitStruct.TIM_Pulse=0;//配置初始CCR计数器值
        TIM_OC1Init(TIM2,&TIM_OCInitStruct);
       
        //**5.开始计数
        TIM_Cmd(TIM2,ENABLE);
}

void set_Zhankongbi(uint16_t  num)
{
        TIM_SetCompare1(TIM2,num);//通过改变CCR的值,从而改变CCR/CNT占空比
}

void set_PSC(uint16_t  num)
{
        TIM_PrescalerConfig(TIM2,num,TIM_PSCReloadMode_Immediate);//改变PSC的值
}       

/***************************************************/IC输入捕获模块
#include "stm32f10x.h"                  // Device header
#include "IC.h"

void IC_init(void)
{
        //**1.打开总的RCC,要配置GPIO从而传入外部时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//打开TMI3,因为定时器2是通用定时器,在APB1总线上
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
        //**2.配置PWM输出引脚PA6
        GPIO_InitTypeDef GPIO_InitStruct;
       
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
        GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
       
        //**选择内部时钟源
        TIM_InternalClockConfig(TIM3);
        //**3.配置时基单元
        //配置为1MHz
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
       
        TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
        TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
        TIM_TimeBaseInitStruct.TIM_Period=65536-1;//设置预装载值   ARR    //外部时钟的话用不了这么高的频率
        TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//设置预分频值   PSC
        TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);//初始化时基单元
        TIM_ClearFlag(TIM3,TIM_FLAG_Update);//初始化时会产生标志位,需要清除
       
        //**4.配置IC模块
        TIM_ICInitTypeDef TIM_ICInitStruct;
        TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;//选择通道一
        TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;//选择上升沿触发
        TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//选择正极性
        TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;//选择一分频
        TIM_ICInitStruct.TIM_ICFilter=0xF;//选择滤波器的值
        TIM_ICInit(TIM3,&TIM_ICInitStruct);
       
        //**5.配置从模式
        TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
        TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
       
        //**6.使能定时器模块,开始计数
        TIM_Cmd(TIM3,ENABLE);
}

uint32_t get_Freq(void)
{
        return 1000000/(TIM_GetCapture1(TIM3)+1) ;
}


/***************************************************/主函数
int main(void)
{
        OLED_Init();
        pwm_init();
        IC_init();
        OLED_ShowString(1,1,"Hello,my honey");
        set_Zhankongbi(50);                        //Freq = 72M / (PSC + 1) / 100
        set_PSC(720 - 1);                        //Duty = CCR / 100
        while(1)
        {
                OLED_ShowNum(2,1,get_Freq(),5);
        }
}
 楼主| t60yz 发表于 2023-11-22 11:45 | 显示全部楼层
5.2.2 PWMI模式同时测频率、占空比
相当于开了TI1FP2的通道去实现读取占空比

占空比是 CCR2记录的高电平持续时间 除以 CCR1记录的整个周期的时间

  1. #include "stm32f10x.h"                  // Device header
  2. #include "OLED.h"
  3. #include "PWM.h"
  4. #include "IC.h"

  5. /***************************************************/PWM模块
  6. #include "stm32f10x.h"                  // Device header


  7. void pwm_init(void)
  8. {
  9.         //**1.打开总的RCC,要配置GPIO从而传入外部时钟
  10.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因为定时器2是通用定时器,在APB1总线上
  11.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  12.         //**2.配置PWM输出引脚
  13.         GPIO_InitTypeDef GPIO_InitStruct;
  14.        
  15.         GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
  16.         GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
  17.         GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
  18.         GPIO_Init(GPIOA,&GPIO_InitStruct);
  19.        
  20.         //**3.配置时基单元
  21.         //配置为1000KHz,分辨率为1%
  22.         TIM_InternalClockConfig(TIM2);//选择内部时钟源
  23.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
  24.        
  25.         TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
  26.         TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
  27.         TIM_TimeBaseInitStruct.TIM_Period=100-1;//设置预装载值       //外部时钟的话用不了这么高的频率
  28.         TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//设置预分频值
  29.         TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
  30.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化时基单元
  31.         TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化时会产生标志位,需要清除

  32.         //**4.配置CCR
  33.         TIM_OCInitTypeDef TIM_OCInitStruct;
  34.        
  35.         TIM_OCStructInit(&TIM_OCInitStruct);//先整体初始化,防止有些变量未初始化而出错
  36.         TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置为PWM1输出模式
  37.         TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF为高极性
  38.         TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置输出使能
  39.         TIM_OCInitStruct.TIM_Pulse=0;//配置初始CCR计数器值
  40.         TIM_OC1Init(TIM2,&TIM_OCInitStruct);
  41.        
  42.         //**5.开始计数
  43.         TIM_Cmd(TIM2,ENABLE);
  44. }

  45. void set_Zhankongbi(uint16_t  num)
  46. {
  47.         TIM_SetCompare1(TIM2,num);//通过改变CCR的值,从而改变CCR/CNT占空比
  48. }

  49. void set_PSC(uint16_t  num)
  50. {
  51.         TIM_PrescalerConfig(TIM2,num,TIM_PSCReloadMode_Immediate);//改变PSC的值
  52. }       

  53. /***************************************************/IC输入捕获模块
  54. #include "stm32f10x.h"                  // Device header
  55. #include "IC.h"

  56. void IC_init(void)
  57. {
  58.         //**1.打开总的RCC,要配置GPIO从而传入外部时钟
  59.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//打开TMI3,因为定时器2是通用定时器,在APB1总线上
  60.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  61.         //**2.配置PWM输出引脚PA6
  62.         GPIO_InitTypeDef GPIO_InitStruct;
  63.        
  64.         GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
  65.         GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
  66.         GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
  67.         GPIO_Init(GPIOA,&GPIO_InitStruct);
  68.        
  69.         //**选择内部时钟源
  70.         TIM_InternalClockConfig(TIM3);
  71.         //**3.配置时基单元
  72.         //配置为1MHz
  73.         TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
  74.        
  75.         TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//设置分频
  76.         TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置向上计数
  77.         TIM_TimeBaseInitStruct.TIM_Period=65536-1;//设置预装载值   ARR    //外部时钟的话用不了这么高的频率
  78.         TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//设置预分频值   PSC
  79.         TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高级计数器功能,重复计数器
  80.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);//初始化时基单元
  81.         TIM_ClearFlag(TIM3,TIM_FLAG_Update);//初始化时会产生标志位,需要清除
  82.        
  83.         //**4.配置IC模块
  84.         TIM_ICInitTypeDef TIM_ICInitStruct;
  85.         TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;//选择通道一
  86.         TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;//选择上升沿触发
  87.         TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//选择正极性
  88.         TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;//选择一分频
  89.         TIM_ICInitStruct.TIM_ICFilter=0xF;//选择滤波器的值
  90.         TIM_ICInit(TIM3,&TIM_ICInitStruct);
  91.         TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);

  92.         //**5.配置从模式
  93.         TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
  94.         TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
  95.        
  96.         //**6.使能定时器模块,开始计数
  97.         TIM_Cmd(TIM3,ENABLE);
  98. }

  99. uint32_t get_Freq(void)
  100. {
  101.         return 1000000/(TIM_GetCapture1(TIM3)+1) ;
  102. }

  103. uint32_t get_Zhankongbi(void)
  104. {
  105.         return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);
  106. }
  107. /***************************************************/主函数
  108. int main(void)
  109. {
  110.         OLED_Init();
  111.         pwm_init();
  112.         IC_init();
  113.         OLED_ShowString(1,1,"Hello,my honey");
  114.         set_Zhankongbi(50);                        //Freq = 72M / (PSC + 1) / 100
  115.         set_PSC(720 - 1);                        //Duty = CCR / 100
  116.         while(1)
  117.         {
  118.                 OLED_ShowNum(2,1,get_Freq(),5);
  119.         OLED_ShowNum(3,1,get_Zhankongbi(),3);
  120.         }
  121. }
 楼主| t60yz 发表于 2023-11-22 11:46 | 显示全部楼层
5.2.3 编码器接口测速(简介)
通过配置定时器,占用了IC捕获模式的两个通道,自动判断两个脚的波形相位差和边沿触发(一般都是使用T1T2模式,可消除毛刺信号)

25922655d797a1f3c6.png



 楼主| t60yz 发表于 2023-11-22 11:46 | 显示全部楼层
 楼主| t60yz 发表于 2023-11-22 11:46 | 显示全部楼层
 楼主| t60yz 发表于 2023-11-22 11:46 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部