• STM32F407 2个高级定时器生成2路无刷电机波形以及相电流采集程序(寄存器版)


    stm32f407 高级定时1、定时8 生成20k 中心PWM 波形 并分别用其通道4 触发ADC1 ADC2 采样 用于分别两无刷电机foc 电流环控制,ADC1产生50us的电流采集完成中断,用于foc算法周期运算

    主要参考高级定时器的寄存器和ADC寄存器

    首先,要使用STM32F407的高级定时器1和定时器8生成20kHz的中心PWM波形,你需要进行以下步骤:

    1. 配置时钟:使能GPIO和相应的定时器时钟。

    2. 配置GPIO:选择用于输出PWM的引脚,并将这些引脚配置为复用功能。

    3. 配置定时器:对定时器1和定时器8进行相应的配置,使其能够生成PWM信号。

      • 配置定时器的基本参数:将定时器的模式设置为PWM模式。
      • 配置定时器的时钟分频器。
      • 配置定时器的周期值,并设置PWM信号的占空比。
    4. 配置ADC:使能ADC1和ADC2的时钟,并对它们进行相应的配置。

      • 配置ADC的时钟分频器。
      • 配置ADC的模式:选择连续模式,使得它们能够不间断地进行采样。
      • 配置ADC的触发源:选择定时器的通道4作为触发源。
    5. 配置ADC中断:使能ADC1的转换完成中断,并编写中断处理函数。在中断处理函数中进行foc算法的周期运算。

    6. 启动定时器和ADC

    1. #include
    2. #include //for downlayer interface include the CHAL port
    3. #include "CHAL_Config.h" //
    4. #define TIM_1_8_CLOCK_HZ 168000000
    5. // #define TIM_1_8_PERIOD_CLOCKS 3500 //24k
    6. #define TIM_1_8_PERIOD_CLOCKS 4199 // 20k
    7. #define TIM_1_8_DEADTIME_CLOCKS 20
    8. #define TIM_APB1_CLOCK_HZ 84000000
    9. #define TIM_APB1_PERIOD_CLOCKS 4096
    10. #define TIM_APB1_DEADTIME_CLOCKS 40
    11. #define TIM_1_8_RCR 2
    12. static void MX_ADC1_Init(void);
    13. static void MX_ADC2_Init(void);
    14. void CHAL_Pwm1Init(char *HIVersion, uint32_t runFreq, uint32_t deadTime, uint32_t sampHalfTime)
    15. {
    16. uint32_t pwmTiks = CPUFREQ / 2 / runFreq;
    17. uint8_t deadTiks = deadTime / CPURATE;
    18. // 使能TIM1时钟
    19. RCC->APB2ENR |= 1 << 0;
    20. // 配置TIM1基本设置
    21. TIM1->CR1 = 0;
    22. TIM1->CR1 |= (1 << 5); // 中心对齐模式 1 递减时产生
    23. TIM1->CR1 |= (1 << 0); // 使能计数器
    24. // TIM1->CR1 |= TIM_CR1_ARPE; // 自动重载预装载使能
    25. // TIM1->CR1 |= TIM_CR1_CKD_0; // 时钟分频因子 = /1
    26. // 设置预分频器和周期
    27. TIM1->PSC = 0; // 预分频器 = 0
    28. TIM1->ARR = pwmTiks; // 周期
    29. // 重复计数器设置(如适用)
    30. TIM1->RCR = TIM_1_8_RCR;
    31. // 配置时钟源
    32. TIM1->CR2 = 0;
    33. // TIM1->CR2 |= TIM_CR2_MMS_1; // 主模式选择:更新事件产生TRGO
    34. TIM1->CCMR1 = 0;
    35. TIM1->CCMR1 |= 7 << 4; // PWM模式
    36. TIM1->CCMR1 |= 1 << 3; // 输出比较预装载使能
    37. TIM1->CCMR1 |= 7 << 12; // PWM模式
    38. TIM1->CCMR1 |= 1 << 11; // 输出比较预装载使能8 重复计数器8 重复计数器寄存器 (TIMx_RCR)寄存器 (TIMx_RCR)
    39. TIM1->CCMR2 = 0;
    40. TIM1->CCMR2 |= 7 << 4; // PWM模式
    41. TIM1->CCMR2 |= 1 << 3; // 输出比较预装载使能
    42. TIM1->CCMR2 |= 7 << 12; // PWM模式
    43. TIM1->CCMR2 |= 1 << 11; // 输出比较预装载使能
    44. // 设置初始脉冲值(通道1、2、3)
    45. TIM1->CCR1 = 0;
    46. TIM1->CCR2 = 0;
    47. TIM1->CCR3 = 0;
    48. TIM1->CCR4 = 1;
    49. // 设置极性(通道1、2、3)
    50. TIM1->CCER = 0;
    51. /* 0 1 2 3 */
    52. /* CCE=1 CCP=0 CCNE=1 CCPN=0 */
    53. /* 0x5 */
    54. TIM1->CCER |= 5 << 0; // 通道1
    55. TIM1->CCER |= 5 << 4; // 通道2
    56. TIM1->CCER |= 5 << 8; // 通道3
    57. TIM1->CCER |= 1 << 12; // 通道4 极性高
    58. // 断开与死区时间配置
    59. TIM1->BDTR = deadTiks; // 最大不超过255 tick
    60. TIM1->BDTR |= 1 << 15; // 输出使能
    61. /* gpio 初始化 */
    62. RCC->AHB1ENR |= 1 << 0; // 使能PORTA口时钟
    63. RCC->AHB1ENR |= 1 << 1; // 使能PORTB口时钟
    64. GPIO_Set(GPIOA, PIN8 | PIN9 | PIN10, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M,
    65. GPIO_PUPD_PD); // PA9,PA10,复用功能,上拉输出
    66. GPIO_AF_Set(GPIOA, 8, 1); // PA8,AF1
    67. GPIO_AF_Set(GPIOA, 9, 1); // PA8,AF1
    68. GPIO_AF_Set(GPIOA, 10, 1); // PA8,AF1
    69. GPIO_Set(GPIOB, PIN13 | PIN14 | PIN15, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M,
    70. GPIO_PUPD_PD); // PA9,PA10,复用功能,上拉输出
    71. GPIO_AF_Set(GPIOB, 13, 1); // PA8,AF1
    72. GPIO_AF_Set(GPIOB, 14, 1); // PA8,AF1
    73. GPIO_AF_Set(GPIOB, 15, 1); // PA8,AF1
    74. MX_ADC1_Init();
    75. }
    76. void CHAL_M1_DisPwm123(void) { TIM1->CCER = 0x1000; }
    77. void CHAL_M1_EnaPwm123(void) { TIM1->CCER = 0x1555; }
    78. void CHAL_Pwm2Init(char *HIVersion, uint32_t runFreq, uint32_t deadTime, uint32_t sampHalfTime)
    79. {
    80. uint32_t pwmTiks = CPUFREQ / 2 / runFreq;
    81. uint8_t deadTiks = deadTime / CPURATE;
    82. // 使能TIM2时钟
    83. RCC->APB2ENR |= 1 << 1;
    84. // 配置TIM2基本设置
    85. TIM8->CR1 = 0;
    86. TIM8->CR1 |= (1 << 5); // 中心对齐模式 1 递减时产生
    87. TIM8->CR1 |= (1 << 0); // 使能计数器
    88. // TIM8->CR1 |= TIM_CR1_ARPE; // 自动重载预装载使能
    89. // TIM8->CR1 |= TIM_CR1_CKD_0; // 时钟分频因子 = /1
    90. // 设置预分频器和周期
    91. TIM8->PSC = 0; // 预分频器 = 0
    92. TIM8->ARR = pwmTiks; // 周期
    93. // 重复计数器设置(如适用)
    94. TIM8->RCR = TIM_1_8_RCR;
    95. // 配置时钟源
    96. TIM8->CR2 = 0;
    97. // TIM8->CR2 |= TIM_CR2_MMS_1; // 主模式选择:更新事件产生TRGO
    98. // PWM模式配置(通道1、2、3)
    99. TIM8->CCMR1 = 0;
    100. TIM8->CCMR1 |= 7 << 4; // PWM模式
    101. TIM8->CCMR1 |= 1 << 3; // 输出比较预装载使能
    102. TIM8->CCMR1 |= 7 << 12; // PWM模式
    103. TIM8->CCMR1 |= 1 << 11; // 输出比较预装载使能
    104. TIM8->CCMR2 = 0;
    105. TIM8->CCMR2 |= 7 << 4; // PWM模式
    106. TIM8->CCMR2 |= 1 << 3; // 输出比较预装载使能
    107. TIM8->CCMR2 |= 7 << 12; // PWM模式
    108. TIM8->CCMR2 |= 1 << 11; // 输出比较预装载使能
    109. // 设置初始脉冲值(通道1、2、3)
    110. TIM8->CCR1 = 0;
    111. TIM8->CCR2 = 0;
    112. TIM8->CCR3 = 0;
    113. TIM8->CCR4 = 1;
    114. // 设置极性(通道1、2、3)
    115. TIM8->CCER = 0;
    116. /* 0 1 2 3 */
    117. /* CCE=1 CCP=0 CCNE=1 CCPN=0 */
    118. /* 0x5 */
    119. TIM8->CCER |= 5 << 0; // 通道1
    120. TIM8->CCER |= 5 << 4; // 通道2
    121. TIM8->CCER |= 5 << 8; // 通道3
    122. TIM8->CCER |= 1 << 12; // 通道4 极性高
    123. // 断开与死区时间配置
    124. TIM8->BDTR = deadTiks; // 最大不超过255 tick
    125. TIM8->BDTR |= 1 << 15; // 输出使能
    126. /* gpio 初始化 */
    127. RCC->AHB1ENR |= 1 << 0; // 使能PORTA口时钟
    128. RCC->AHB1ENR |= 1 << 1; // 使能PORTB口时钟
    129. RCC->AHB1ENR |= 1 << 2; // 使能PORTc口时钟
    130. GPIO_Set(GPIOA, PIN7, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M,
    131. GPIO_PUPD_PD); // PA9,PA10,复用功能,上拉输出
    132. GPIO_AF_Set(GPIOA, 7, 3); // PA8,AF3
    133. GPIO_Set(GPIOB, PIN0 | PIN1 | PIN15, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M,
    134. GPIO_PUPD_PD); // PA9,PA10,复用功能,上拉输出
    135. GPIO_AF_Set(GPIOB, 0, 3); // PA8,AF1
    136. GPIO_AF_Set(GPIOB, 1, 3); // PA8,AF1
    137. GPIO_Set(GPIOC, PIN6 | PIN7 | PIN8, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M,
    138. GPIO_PUPD_PD); // PA9,PA10,复用功能,上拉输出
    139. GPIO_AF_Set(GPIOC, 6, 3); // PA8,AF1
    140. GPIO_AF_Set(GPIOC, 7, 3); // PA8,AF1
    141. GPIO_AF_Set(GPIOC, 8, 3); // PA8,AF1
    142. MX_ADC2_Init();
    143. }
    144. void CHAL_M2_DisPwm123(void) { TIM8->CCER = 0x1000; }
    145. void CHAL_M2_EnaPwm123(void) { TIM8->CCER = 0x1555; }
    146. /**
    147. * @brief ADC1 初始化函数
    148. * @param 无
    149. * @retval 无
    150. */
    151. static void MX_ADC1_Init(void)
    152. {
    153. // 使能ADC1时钟
    154. RCC->APB2ENR |= 1 << 8;
    155. // ADC1->CR1 = 0x180;
    156. ADC1->CR1 |= 1 << 8; // 使能扫描模式
    157. ADC1->CR1 |= 1 << 7; // 注入通道中断完成中断使能
    158. ADC1->CR2 = 0;
    159. ADC1->CR2 |= 1 << 10; // ADC 使能
    160. ADC1->CR2 |= 2 << 20; // 下降沿触发 注入通道检测
    161. ADC1->CR2 |= 0 << 16; // 注入通道 TIM1 CC4 事件
    162. ADC1->CR2 |= 1 << 0; // ADC 使能
    163. ADC1->HTR = 0x0FFF;
    164. // ADC1->CR2 = 0x0200401;
    165. ADC1->HTR = 0x0FFF;
    166. ADC1->JSQR = 0;
    167. ADC1->JSQR |= 1 << 20; // 注入通道序列长度:2
    168. ADC1->JSQR |= (10 << 10); // 注入通道3 对应 adc 通道
    169. ADC1->JSQR |= (11 << 15); // 注入通道4
    170. ADC1->SMPR1 = 0;
    171. ADC1->SMPR1 |= 0 << 0; // 注入通道8采样时间: 3个周期
    172. ADC1->SMPR1 |= 0 << 3; // 注入通道12采样时间:3个周期
    173. RCC->AHB1ENR |= 1 << 2; // 使能PORTC口时钟
    174. GPIO_Set(GPIOC, PIN0 | PIN1, GPIO_MODE_AIN, 0, 0, GPIO_PUPD_PU); //
    175. // // 启动ADC1
    176. MY_NVIC_Init(0, 0, ADC_IRQn, 0); // 抢占1,子优先级3,组2
    177. }
    178. /**
    179. * @brief ADC2 初始化函数
    180. * @param 无
    181. * @retval 无
    182. */
    183. static void MX_ADC2_Init(void)
    184. {
    185. // 使能ADC2时钟
    186. RCC->APB2ENR |= 1 << 9;
    187. // ADC2->CR1 = 0x180;
    188. ADC2->CR1 = 0;
    189. ADC2->CR1 |= 1 << 8; // 使能扫描模式
    190. ADC2->CR2 = 0;
    191. ADC2->CR2 |= 1 << 10; // ADC 使能
    192. ADC2->CR2 |= 2 << 20; // 下降沿触发 注入通道检测
    193. ADC2->CR2 |= 0xe << 16; // 注入通道 TIM8 CC4 事件
    194. ADC2->CR2 |= 1 << 0; // ADC 使能
    195. ADC2->HTR = 0x0FFF;
    196. // // // 配置注入通道(通道8、12、6、13)
    197. ADC2->JSQR = 0;
    198. ADC2->JSQR |= 1 << 20; // 注入通道序列长度:2
    199. ADC2->JSQR |= (12 << 10); // 注入通道3
    200. ADC2->JSQR |= (13 << 15); // 注入通道4
    201. ADC2->SMPR1 = 0;
    202. ADC2->SMPR1 |= 0 << 0; // 注入通道8采样时间: 3个周期
    203. ADC2->SMPR1 |= 0 << 3; // 注入通道12采样时间:3个周期
    204. RCC->AHB1ENR |= 1 << 2; // 使能PORTC口时钟
    205. GPIO_Set(GPIOC, PIN2 | PIN3, GPIO_MODE_AIN, 0, 0, GPIO_PUPD_PU); //
    206. }

  • 相关阅读:
    Fedora 35 部署DNS主从和分离解析 —— 筑梦之路
    信创服务器操作系统的适配迁移分析
    迁移学习——ResNet152
    Qt实现XYModem协议(八)
    Android 从我方界面启动三方界面,如何巧妙地检测三方页面的生命周期呢?
    039-第三代软件开发-PDF阅读器
    正则表达式30分钟入门教程
    初学Vue(全家桶)-第18天(vue3):compositionAPI-组合API
    Jessibuca 插件播放直播流视频
    产品经理考PMP有用吗?
  • 原文地址:https://blog.csdn.net/weixin_38604759/article/details/138925490