震动马达实现库函数版(STC8)
震动马达实现库函数版(STC8)
硬件连接
震动马达通常连接在单片机的PWM输出引脚上,例如P1.5(对应PWM2通道)。需确保马达驱动电路包含三极管或MOS管放大电流,并反向并联续流二极管保护。
STC8 PWM库函数配置
#include "GPIO.h"
#include "Delay.h"
#include "UART.h" // 串口配置 UART_Configuration
#include "NVIC.h" // 中断初始化NVIC_UART1_Init
#include "Switch.h" // 引脚切换 UART1_SW_P30_P31
#include "STC8H_PWM.h"// 宏定义,给引脚起别名
#define MOTOR P01void GPIO_config() { GPIO_InitTypeDef info;// ===== UART1 P30 P31 准双向info.Mode = GPIO_PullUp; // 准双向info.Pin = GPIO_Pin_0 | GPIO_Pin_1; // 引脚GPIO_Inilize(GPIO_P3, &info);//推挽输出 P01P0_MODE_OUT_PP(GPIO_Pin_1); // 推挽输出默认是高电平MOTOR = 0; // 建议拉低
}// 串口配置函数的定义
void UART_config(void) {// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<COMx_InitDefine COMx_InitStructure; //结构定义COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31); // 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}// PWMB 配置
#define PERIOD (MAIN_Fosc / 1000)
void PWM_config(void)
{PWMx_InitDefine PWMx_InitStructure;// 配置PWM6PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE1; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2PWMx_InitStructure.PWM_Duty = 0.0 * PERIOD; //PWM占空比时间, 0~PeriodPWMx_InitStructure.PWM_EnoSelect = ENO6P; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM6, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB// 配置PWMBPWMx_InitStructure.PWM_Period = PERIOD - 1; //周期时间, 0~65535PWMx_InitStructure.PWM_DeadTime = 0; //死区发生器设置, 0~255PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLEPWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLEPWM_Configuration(PWMB, &PWMx_InitStructure); //初始化PWM通用寄存器, PWMA,PWMB// 切换PWM通道PWM6_SW(PWM6_SW_P01); //PWM6_SW_P21,PWM6_SW_P54,PWM6_SW_P01,PWM6_SW_P75// 初始化PWMB的中断NVIC_PWM_Init(PWMB,DISABLE,Priority_0);
}// 更新PWM占空比
void Update_pwm_duty(char value) { // 0 ~ 100PWMx_Duty duty;duty.PWM6_Duty = (value / 100.0) * PERIOD;UpdatePwm(PWM6, &duty);
}void main() {char i = 0;EAXSFR(); /* 扩展寄存器访问使能 */EA = 1; // 使能中断总开关GPIO_config(); // GPIO配置UART_config(); // 串口配置PWM_config(); // 调用PWM配置// 逐渐增强for(i = 0; i <= 100; i += 5) {Update_pwm_duty(i);delay_ms(250);}Update_pwm_duty(0);while (1){}
}
震动强度控制
通过修改占空比寄存器控制震动强度:
// 更新PWM占空比
void Update_pwm_duty(char value) { // 0 ~ 100PWMx_Duty duty;duty.PWM6_Duty = (value / 100.0) * PERIOD;UpdatePwm(PWM6, &duty);
}
定时震动模式
利用定时器实现间歇震动:
void Timer0_ISR()
{static uint8_t counter = 0;if(++counter >= 20) { // 约1秒切换状态counter = 0;PWMB_CCER2 ^= 0x01; // 切换PWM输出状态}
}
案例
#include "GPIO.h"
#include"Delay.h"
#include "UART.h"
#include "NVIC.h"
#include "Switch.h"
#include "STC8H_PWM.h"
#include "Timer.h"#define MOTOR P01
int i = 0;void GPIO_config(void) {GPIO_InitTypeDef GPIO_InitStructure; //结构定义GPIO_InitStructure.Pin = GPIO_Pin_0 |GPIO_Pin_1; //指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P3, &GPIO_InitStructure);//初始化//推挽输出 P01P0_MODE_OUT_PP(GPIO_Pin_1);MOTOR = 0 ;
}
void UART_config(void) {// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<COMx_InitDefine COMx_InitStructure; //结构定义COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31); // 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}#define PERIOD (MAIN_Fosc / 1000)
void PWM_config(void)
{PWMx_InitDefine PWMx_InitStructure;// 配置PWM6PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE1; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2PWMx_InitStructure.PWM_Duty = 0.0 * PERIOD; //PWM占空比时间, 0~PeriodPWMx_InitStructure.PWM_EnoSelect = ENO6P; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM6, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB// 配置PWMBPWMx_InitStructure.PWM_Period = PERIOD - 1; //周期时间, 0~65535PWMx_InitStructure.PWM_DeadTime = 0; //死区发生器设置, 0~255PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLEPWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLEPWM_Configuration(PWMB, &PWMx_InitStructure); //初始化PWM通用寄存器, PWMA,PWMB// 切换PWM通道PWM6_SW(PWM6_SW_P01); //PWM6_SW_P21,PWM6_SW_P54,PWM6_SW_P01,PWM6_SW_P75// 初始化PWMB的中断NVIC_PWM_Init(PWMB,DISABLE,Priority_0);
}
void pwm_set_duty(char value){PWMx_Duty duty ;duty.PWM6_Duty = (value/100.0)*PERIOD;UpdatePwm(PWM6, &duty);}
void Timer_config(void)
{TIM_InitTypeDef TIM_InitStructure; //结构定义//定时器0做16位自动重装, 中断频率为1000HZTIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMaskTIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_ExtTIM_InitStructure.TIM_ClkOut = DISABLE; //是否输出高速脉冲, ENABLE或DISABLETIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / 1000UL); //初值,TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLETimer_Inilize(Timer0,&TIM_InitStructure); //初始化Timer0 Timer0,Timer1,Timer2,Timer3,Timer4NVIC_Timer0_Init(ENABLE,Priority_0); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
}
// 更新PWM占空比
void Update_pwm_duty(char value) { // 0 ~ 100PWMx_Duty duty;duty.PWM6_Duty = (value / 100.0) * PERIOD;UpdatePwm(PWM6, &duty);
}
void timer0_call(){// TODO: 在此处添加用户代码i++;if (i == 10000) { // 1000个1ms才进入1次 每隔1s,震动1次P01 = !P01;Update_pwm_duty(i);printf("i = %d\r\n",i);i = 0; // 重置}
}
void main() {EAXSFR ();EA = 1;GPIO_config();UART_config();PWM_config();Timer_config();while (1){
}
}
注意事项
- 需根据实际马达工作电压调整PWM频率(通常500Hz-2kHz)
- 马达两端建议并联0.1μF电容滤波
- 长时间工作时需注意散热
- STC8系列需先设置I/O口模式再配置PWM
典型调用示例
1.串口结合pwm控制震动马达
#include "GPIO.h"
#include "Delay.h"
#include "STC8H_PWM.h"
#include "NVIC.h"
#include "Switch.h"
#include "UART.h"void GPIO_config(void) {GPIO_InitTypeDef GPIO_InitStructure; //结构定义// UART1: P30 P31 准双向口GPIO_InitStructure.Pin = GPIO_Pin_0 | GPIO_Pin_1; //指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P3, &GPIO_InitStructure);//初始化// P01 推挽输出GPIO_InitStructure.Pin = GPIO_Pin_1; //指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化
}// 1000为频率,1秒钟执行1000次
#define PERIOD (MAIN_Fosc / 1000)void PWM_config(void)
{PWMx_InitDefine PWMx_InitStructure;// 配置PWM6PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE1; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2PWMx_InitStructure.PWM_Duty = 0; //PWM占空比时间, 0~PeriodPWMx_InitStructure.PWM_EnoSelect = ENO6P; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM6, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB// 配置PWMBPWMx_InitStructure.PWM_Period = PERIOD - 1; //周期时间, 0~65535PWMx_InitStructure.PWM_DeadTime = 0; //死区发生器设置, 0~255PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLEPWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLEPWM_Configuration(PWMB, &PWMx_InitStructure); //初始化PWM通用寄存器, PWMA,PWMB// 切换PWM通道PWM6_SW(PWM6_SW_P01); //PWM6_SW_P21,PWM6_SW_P54,PWM6_SW_P01,PWM6_SW_P75// 初始化PWMB的中断NVIC_PWM_Init(PWMB,DISABLE,Priority_0);
}void UART_config(void) {// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<COMx_InitDefine COMx_InitStructure; //结构定义COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31); // 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}void on_uart1_recv(u8 buf1) {// 静态变量,只会初始化1次,不释放static PWMx_Duty duty; // 占空比结构体变量static char d = 100;// 串口不断接收到0x1,震动逐渐减弱,如果是停止,震动强度从最强的模式重来if (buf1 == 0x01) { // 减少占空比d -= 5;if (d < 0) { // < 0时,重新开始d = 100;}}printf("d = %d\n", (int)d);// 设置比例数字duty.PWM6_Duty = d * PERIOD / 100.0;// 更新占空比UpdatePwm(PWM6, &duty);
}void main() {u8 d = 0, i;EAXSFR(); /* 扩展寄存器访问使能 */// IO配置GPIO_config();PWM_config();UART_config();// 开启全局中断EA = 1;while (1) {delay_ms(20);if(COM1.RX_TimeOut > 0) {//超时计数if(--COM1.RX_TimeOut == 0) {if(COM1.RX_Cnt > 0) {for(i=0; i<COM1.RX_Cnt; i++) {// RX1_Buffer[i]存的是接收的数据,写出用 TX1_write2buff// TODO: 做具体的逻辑TX1_write2buff(RX1_Buffer[i]); // 原数据发送on_uart1_recv(RX1_Buffer[i]);}}COM1.RX_Cnt = 0;}}}
}