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

    }
}
相关推荐
你好,奋斗者!12 小时前
单片机引脚的高电平和低电平范围值
单片机·嵌入式硬件·嵌入式软件
眰恦ゞLYF13 小时前
嵌入式硬件——IMX6ULL时钟配置
单片机·嵌入式硬件·时钟·imx6ull
小莞尔13 小时前
【51单片机】【protues仿真】基于51单片机秒表系统(LCD1602多功能、可保持30条记录)
c语言·stm32·单片机·嵌入式硬件·51单片机
Tolines14 小时前
PCIe外接卡标准尺寸
嵌入式硬件·硬件工程·设计规范
寅双木14 小时前
常见的九种二极管
笔记·嵌入式硬件·稳压二极管·tvs·肖特基二极管·发光二极管·齐纳击穿
Black doncky prince14 小时前
QR反激电源副边整流二极管电压波形分析
单片机·嵌入式硬件·硬件工程
currycheng614 小时前
开关电源测试及方法
单片机·嵌入式硬件·硬件架构·硬件工程
SundayBear15 小时前
基于MCU的文件系统
linux·服务器·单片机
DIY机器人工房21 小时前
关于解决 libwebsockets 库编译时遇到的问题的方法:
服务器·stm32·单片机·嵌入式硬件·tcp
GilgameshJSS1 天前
STM32H743-ARM例程3-SYSTICK定时闪烁LED
arm开发·stm32·单片机·嵌入式硬件·学习