目的:用MCTM的通道2和通道3控制两个SG90舵机(180°)
步骤:
参考江科大的PPT
1. 开启GPIO时钟,AFIO时钟,MCTM0时钟;
CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }}; CKCUClock.Bit.MCTM0 = 1; CKCUClock.Bit.PD = 1; CKCUClock.Bit.AFIO = 1; CKCU_PeripClockConfig(CKCUClock, ENABLE);
2.端口复用为PWM模式(PD1和PD3引脚);
AFIO_GPxConfig(PWM_GPIO, PWM_Pin1 | PWM_Pin2, AFIO_MODE_4);//端口复用为AF4模式
3. GPIO引脚配置为复用推挽输出;
GPIO_DirectionConfig(PWM_PORT, PWM_Pin1, GPIO_DIR_OUT); GPIO_DirectionConfig(PWM_PORT, PWM_Pin2, GPIO_DIR_OUT);
4. 配置时基单元;
SG90舵机要求的PWM信号周期是20ms。ht32默认系统时钟主频为48Mhz, 48分频后得到1Mhz, 重装载值CRR设为20K,1Mhz/20K = 50hz, 得到周期20ms。
TM_TimeBaseInitTypeDef TM_TimeBaseInitStruct; // 声明结构体 TM_TimeBaseInitStruct.Prescaler = PSC; // 预分频系数 TM_TimeBaseInitStruct.CounterReload = CRR; // 计数周期,重载值 TM_TimeBaseInitStruct.RepetitionCounter = 0; TM_TimeBaseInitStruct.CounterMode = TM_CNT_MODE_UP; // 向上计数 TM_TimeBaseInitStruct.PSCReloadTime = TM_PSC_RLD_IMMEDIATE;// 立即重装载 TM_TimeBaseInit(HT_MCTM0, &TM_TimeBaseInitStruct); TM_IntConfig(HT_MCTM0, TM_INT_UEV, DISABLE); //关闭定时器中断
5. 配置输出比较单元;
TM_OutputInitTypeDef TM_OutputInitStructure; //输出配置结构体 TM_OutputStructInit(&TM_OutputInitStructure); //初始化结构体默认值 //通道2 TM_OutputInitStructure.Channel = TM_CH_2; TM_OutputInitStructure.OutputMode = TM_OM_PWM1; //输出比较模式TM_OutputInitStructure.Polarity = TM_CHP_NONINVERTED; //输出比较极性 TM_OutputInitStructure.Control = TM_CHCTL_ENABLE; //使能 TM_OutputInitStructure.Compare = 0; //CCR值 TM_OutputInit(HT_MCTM0, &TM_OutputInitStructure); //通道3 TM_OutputInitStructure.Channel = TM_CH_3; TM_OutputInitStructure.OutputMode = TM_OM_PWM1; //输出比较模式 TM_OutputInitStructure.Polarity = TM_CHP_NONINVERTED; //输出比较极性 TM_OutputInitStructure.Control = TM_CHCTL_ENABLE; //使能 TM_OutputInitStructure.Compare = 0; //CCR值 TM_OutputInit(HT_MCTM0, &TM_OutputInitStructure);
6. 使能定时器counter和MCTM的主输出
TM_Cmd(HT_MCTM0, ENABLE); // 开启GPTM0 MCTM_CHMOECmd(HT_MCTM0, ENABLE);//!!!!!!!!注意一定要加这个使能主输出
Servo.h
#ifndef __SERVO_H
#define __SERVO_H
#include "ht32.h"
#include "DELAY.h"
#include "OLED.h"
#include "DELAY.h"
/* 180°舵机*/
#define PSC 48-1
#define CRR 20000-1
//舵机GPIO
#define PWM_GPIO GPIO_PD
#define PWM_PORT HT_GPIOD
//舵机1
#define PWM_Pin1 AFIO_PIN_1 //CH2
//舵机2
#define PWM_Pin2 AFIO_PIN_3 //CH3
void Servo_Init(void);
void Servo_Run(uint8_t num, uint16_t angle);
void Close(void);
void Open(void);
#endif
Servo.c
#include "Servo.h"
/* 舵机初始化 */
void Servo_Init()
{
//开启时钟
CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
CKCUClock.Bit.MCTM0 = 1;
CKCUClock.Bit.PD = 1;
CKCUClock.Bit.AFIO = 1;
CKCU_PeripClockConfig(CKCUClock, ENABLE);
//端口复用重映射
AFIO_GPxConfig(PWM_GPIO, PWM_Pin1 | PWM_Pin2, AFIO_MODE_4);//端口复用为AF4模式
//GPIO配置
GPIO_DirectionConfig(PWM_PORT, PWM_Pin1, GPIO_DIR_OUT);
GPIO_DirectionConfig(PWM_PORT, PWM_Pin2, GPIO_DIR_OUT);
//配置时基单元
/*ht32默认系统时钟主频为48Mhz, 48分频->1Mhz, 重装载值20K,1Mhz/20K = 50hz, 周期20ms*/
TM_TimeBaseInitTypeDef TM_TimeBaseInitStruct; // 声明结构体
TM_TimeBaseInitStruct.Prescaler = PSC; // 预分频系数
TM_TimeBaseInitStruct.CounterReload = CRR; // 计数周期,重载值
TM_TimeBaseInitStruct.RepetitionCounter = 0;
TM_TimeBaseInitStruct.CounterMode = TM_CNT_MODE_UP; // 向上计数
TM_TimeBaseInitStruct.PSCReloadTime = TM_PSC_RLD_IMMEDIATE;// 立即重装载
TM_TimeBaseInit(HT_MCTM0, &TM_TimeBaseInitStruct);
TM_IntConfig(HT_MCTM0, TM_INT_UEV, DISABLE); //关闭定时器中断
//配置输出比较单元
TM_OutputInitTypeDef TM_OutputInitStructure; //输出配置结构体
TM_OutputStructInit(&TM_OutputInitStructure); //初始化结构体默认值
//通道2
TM_OutputInitStructure.Channel = TM_CH_2;
TM_OutputInitStructure.OutputMode = TM_OM_PWM1; //输出比较模式
TM_OutputInitStructure.Polarity = TM_CHP_NONINVERTED; //输出比较极性
TM_OutputInitStructure.Control = TM_CHCTL_ENABLE; //使能
TM_OutputInitStructure.Compare = 0; //CCR值
TM_OutputModeConfig(HT_MCTM0, TM_CH_2,TM_OM_PWM1);
TM_OutputInit(HT_MCTM0, &TM_OutputInitStructure);
//通道3
TM_OutputInitStructure.Channel = TM_CH_3;
TM_OutputInitStructure.OutputMode = TM_OM_PWM1; //输出比较模式
TM_OutputInitStructure.Polarity = TM_CHP_NONINVERTED; //输出比较极性
TM_OutputInitStructure.Control = TM_CHCTL_ENABLE; //使能
TM_OutputInitStructure.Compare = 0; //CCR值
TM_OutputModeConfig(HT_MCTM0, TM_CH_3,TM_OM_PWM1);
TM_OutputInit(HT_MCTM0, &TM_OutputInitStructure);
TM_ClearFlag(HT_MCTM0, TM_FLAG_UEV);
TM_Cmd(HT_MCTM0, ENABLE); // 开启GPTM0
MCTM_CHMOECmd(HT_MCTM0, ENABLE);
}
/**
* 功能:舵机驱动测试代码(可从0~180,每45度旋转一次)
* 参数:num : 对应的舵机 1:通道2 2:通道3
angle ;舵机旋转度数(相对角度)
* 返回值:None
*/
void Servo_Run(uint8_t num, uint16_t angle)
{
if(num == 1)
{
switch(angle)
{
case 180 :TM_SetCaptureCompare(HT_MCTM0,TM_CH_2,2500); break;//对应180度
case 135 :TM_SetCaptureCompare(HT_MCTM0,TM_CH_2,2000); break;//对应135度
case 90 :TM_SetCaptureCompare(HT_MCTM0,TM_CH_2,1500); break;//对应90度
case 45 :TM_SetCaptureCompare(HT_MCTM0,TM_CH_2,1000); break;//对应45度
case 0 :TM_SetCaptureCompare(HT_MCTM0,TM_CH_2,500); break;//对应0度
}
}
else if(num == 2)
{
switch(angle)
{
case 180 :TM_SetCaptureCompare(HT_MCTM0,TM_CH_3,2500); break;//对应180度
case 135 :TM_SetCaptureCompare(HT_MCTM0,TM_CH_3,2000); break;//对应135度
case 90 :TM_SetCaptureCompare(HT_MCTM0,TM_CH_3,1500); break;//对应90度
case 45 :TM_SetCaptureCompare(HT_MCTM0,TM_CH_3,1000); break;//对应45度
case 0 :TM_SetCaptureCompare(HT_MCTM0,TM_CH_3,500); break;//对应0度
}
}
}
/**
* 功能:关窗遮阳 0到180
* 参数: None
* 返回值:None
*/
void Close()
{
unsigned int i=0;
for(i=0; i<=2000; i=i+50)
{
TM_SetCaptureCompare(HT_MCTM0,TM_CH_2,i + 500);
TM_SetCaptureCompare(HT_MCTM0,TM_CH_3,i + 500);
DELAY_ms(100);
OLED_ShowNum(2*16+3*8+2*8+4,2*16,i,4,OLED_8X16);
OLED_Update();
}
}
/**
* 功能:开窗 180到0
* 参数: None
* 返回值:None
*/
void Open()
{
unsigned int i=0;
for(i=0; i<=2000; i=i+50)
{
TM_SetCaptureCompare(HT_MCTM0,TM_CH_2,2500 - i);
TM_SetCaptureCompare(HT_MCTM0,TM_CH_3,2500 - i);
DELAY_ms(100);
OLED_ShowNum(2*16+3*8+2*8+4,2*16,i,4,OLED_8X16);
OLED_Update();
}
}