震动马达实现库函数版(STC8)

震动马达实现库函数版(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){ 
}
}

注意事项

  1. 需根据实际马达工作电压调整PWM频率(通常500Hz-2kHz)
  2. 马达两端建议并联0.1μF电容滤波
  3. 长时间工作时需注意散热
  4. 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;
            }
        }

    }
}
相关推荐
玉~你还好吗2 小时前
【嵌入式电机控制#补充3】SDK电机控制台的功能
单片机·嵌入式硬件·嵌入式系统·电机控制·控制算法
zhmc7 小时前
MCU编程中的临界资源及临界区
单片机·嵌入式硬件
智者知已应修善业8 小时前
【51单片机2个按键控制流水灯转向】2022-10-25
c语言·经验分享·笔记·嵌入式硬件·51单片机
写点什么呢9 小时前
Stlink识别不到-安装驱动
stm32·单片机·嵌入式硬件·学习
善 .10 小时前
单片机输出高电平的两种方式
单片机·嵌入式硬件
安庆平.Я10 小时前
STM32——时钟系统
stm32·单片机·嵌入式硬件
机器视觉知识推荐、就业指导20 小时前
STM32 外设驱动模块四:光敏电阻(LDR) 模块
stm32·单片机·嵌入式硬件
ShiMetaPi20 小时前
GM3568JHF:FPGA+ARM异构开发板环境搭建教程
嵌入式硬件·fpga开发
Hello_Embed21 小时前
STM32HAL 快速入门(三):从 HAL 函数到寄存器操作 —— 理解 HAL 库的本质
c语言·stm32·单片机·嵌入式硬件·学习