震动马达实现库函数版(STC8)
硬件连接
震动马达通常连接在单片机的PWM输出引脚上,例如P1.5(对应PWM2通道)。需确保马达驱动电路包含三极管或MOS管放大电流,并反向并联续流二极管保护。
STC8 PWM库函数配置
c
#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 P01
void 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);
//推挽输出 P01
P0_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_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
UART1_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;
// 配置PWM6
PWMx_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_MODE2
PWMx_InitStructure.PWM_Duty = 0.0 * PERIOD; //PWM占空比时间, 0~Period
PWMx_InitStructure.PWM_EnoSelect = ENO6P; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
PWM_Configuration(PWM6, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB
// 配置PWMB
PWMx_InitStructure.PWM_Period = PERIOD - 1; //周期时间, 0~65535
PWMx_InitStructure.PWM_DeadTime = 0; //死区发生器设置, 0~255
PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLE
PWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLE
PWM_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 ~ 100
PWMx_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){
}
}
震动强度控制
通过修改占空比寄存器控制震动强度:
c
// 更新PWM占空比
void Update_pwm_duty(char value) { // 0 ~ 100
PWMx_Duty duty;
duty.PWM6_Duty = (value / 100.0) * PERIOD;
UpdatePwm(PWM6, &duty);
}
定时震动模式
利用定时器实现间歇震动:
c
void Timer0_ISR()
{
static uint8_t counter = 0;
if(++counter >= 20) { // 约1秒切换状态
counter = 0;
PWMB_CCER2 ^= 0x01; // 切换PWM输出状态
}
}
案例
c
#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_PP
GPIO_Inilize(GPIO_P3, &GPIO_InitStructure);//初始化
//推挽输出 P01
P0_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_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
UART1_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;
// 配置PWM6
PWMx_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_MODE2
PWMx_InitStructure.PWM_Duty = 0.0 * PERIOD; //PWM占空比时间, 0~Period
PWMx_InitStructure.PWM_EnoSelect = ENO6P; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
PWM_Configuration(PWM6, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB
// 配置PWMB
PWMx_InitStructure.PWM_Period = PERIOD - 1; //周期时间, 0~65535
PWMx_InitStructure.PWM_DeadTime = 0; //死区发生器设置, 0~255
PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLE
PWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLE
PWM_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位自动重装, 中断频率为1000HZ
TIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
TIM_InitStructure.TIM_ClkOut = DISABLE; //是否输出高速脉冲, ENABLE或DISABLE
TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / 1000UL); //初值,
TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE
Timer_Inilize(Timer0,&TIM_InitStructure); //初始化Timer0 Timer0,Timer1,Timer2,Timer3,Timer4
NVIC_Timer0_Init(ENABLE,Priority_0); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
}
// 更新PWM占空比
void Update_pwm_duty(char value) { // 0 ~ 100
PWMx_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控制震动马达
c
#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_PP
GPIO_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_PP
GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化
}
// 1000为频率,1秒钟执行1000次
#define PERIOD (MAIN_Fosc / 1000)
void PWM_config(void)
{
PWMx_InitDefine PWMx_InitStructure;
// 配置PWM6
PWMx_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_MODE2
PWMx_InitStructure.PWM_Duty = 0; //PWM占空比时间, 0~Period
PWMx_InitStructure.PWM_EnoSelect = ENO6P; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
PWM_Configuration(PWM6, &PWMx_InitStructure); //初始化PWM, PWMA,PWMB
// 配置PWMB
PWMx_InitStructure.PWM_Period = PERIOD - 1; //周期时间, 0~65535
PWMx_InitStructure.PWM_DeadTime = 0; //死区发生器设置, 0~255
PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主输出使能, ENABLE,DISABLE
PWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能计数器, ENABLE,DISABLE
PWM_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_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
UART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4
NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
UART1_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;
}
}
}
}