STC8H系列 驅動步進電機

STC8H 驅動步進電機

  • 一、引言
  • 二、硬件設計
  • 三、軟件設計
    • Step_Motor2.c文件
    • Step_ Motor2.h文件

一、引言

在這里插入圖片描述
眾所周知STC8H系列有兩個PWM,分別為PWMA和PWMB外設模塊,我全都用上,豈不是就有兩個帶動電機的脈沖信號?!哈哈哈哈哈哈
說實在的 只能給出單獨兩個脈沖信號真的很可憐,沒有STM定時器那么靈活。

那么就續STC論壇的梁工 STC8H系列-高級PWM-兩相步進電機-細分驅動 (具有類似梯型加減功能)制作出另外一條PWMB通道輸出脈沖信號帶動電機。

在這里插入圖片描述

二、硬件設計

主要是以STC8H8K64U的MUC使用引腳如下:
在這里插入圖片描述
使用P2.3引腳作為PWMB的輸出信號,PWMA的就不展示了可使用梁工的代碼看實際效果。

三、軟件設計

梁工給出的例子如下:


#define MAIN_Fosc		24000000UL	//定義主時鐘#include	"..\STC8Hxxx.h"/*************	功能說明	**************用高級PWMA匹配取反輸出脈沖控制步進電機驅動器.
為了簡單, 利于初學者, 本例使用線性加減速, 如要使用別的加減速算法, 用戶自行設計.使用外設:
Timer0: 工作于1ms中斷, 提供1ms時隙標志和串口超時處理.
Timer2: 串口1波特率.
串口1:  命令控制, 串口設置115200,8,1,n.
PWMA1P: 從P1.0輸出驅動脈沖, 低驅動, 接步進電機驅動器脈沖輸入端(一般是光耦輸入, 低有效).從P1.1輸出轉向信號, 接步進電機驅動器方向輸入端(一般是光耦輸入, 低有效), 1:順時針(正轉), 0:逆時針(反轉).串口命令設置:
L1,500,1000   --> 馬達1以500Hz正轉1000個脈沖, 脈沖數為0則連續轉動.
R1,500,1000   --> 馬達1以500Hz反轉1000個脈沖, 脈沖數為0則連續轉動
s             --> 停止所有電機******************************************//*************	本地常量聲明	**************//*************	本地變量聲明	**************/u16	M1_CCAP1_tmp;
u8	M1_PWMA_ISR_En;	//每個通道可以單獨允許中斷處理, bit4:通道4, bit3:通道3, bit2:通道2, bit1:通道1.//================== 步進電機相關變量定義 ===================
sbit	M1_P_DIR   = P1^1;	// 運行方向, 接步進電機驅動器方向輸入端(一般是光耦輸入, 低有效), 1:順時針(正轉), 0:逆時針(反轉)
sbit	M1_P_PULSE = P1^0;	// 驅動脈沖, 低驅動, 接步進電機驅動器脈沖輸入端(一般是光耦輸入, 低有效).
sbit	M1_tmp = P1^2;	// 驅動脈沖, 低驅動, 接步進電機驅動器脈沖輸入端(一般是光耦輸入, 低有效).bit		M1_B_RunEn;				//運行允許
bit		M1_f1_update;			//請求刷新頻率值
u16		M1_f1_period;			//當前頻率對應的周期(半周期)(中斷使用, 應用層不可操作)
u16		M1_f1_period_set;	//需要刷新的目標頻率對應的周期(半周期)
u16		M1_f1;							//當前頻率
u16		M1_f1_set;					//目標頻率
u16		M1_f1_step;				//加減速頻率變化的步長
u16		M1_UpPulse;		//加(減)速脈沖數
u16		M1_PulseCnt;	//電機運行總脈沖數, 為0則連續運行
u16		M1_DownCnt;		//運行到要減速輸出的脈沖數
//===========================================================//================== 串口相關變量定義 =======================
#define	RX1_LENGTH	32
u8		RX1_Cnt;		//接收字節計數
u8		RX1_TimerOut;	//接收超時計數
u8		xdata RX1_Buffer[RX1_LENGTH];	//接收緩沖
bit 	B_RX1_OK;		//接收到一塊數據
bit		B_TX1_Busy;		//發送忙標志
//===========================================================bit	B_1ms;	//1ms時隙標志/*************	本地函數聲明	**************/
void 	PWMA_config(void);
u8		Timer0_Config(u8 t, u32 reload);	//t=0: reload值是主時鐘周期數,  t=1: reload值是時間(單位us), 返回0正確, 返回1裝載值過大錯誤.
void	UART1_config(u32 brt, u8 timer, u8 io);	// brt: 通信波特率,  timer=2: 波特率使用定時器2, 其它值: 使用Timer1做波特率. io=0: 串口1切換到P3.0 P3.1,  =1: 切換到P3.6 P3.7,  =2: 切換到P1.6 P1.7,  =3: 切換到P4.3 P4.4
void 	UART1_PrintString(u8 *puts);
void 	UART1_TxByte(u8 dat);		// 串口1發送一個字節	
void 	RX1_process(void);			// 串口1處理函數
u16		GetStep(u16 f, u16 f_set);	// 計算速度變化步進長度
void	GetFreq1(void);				// 計算加減速頻率
void	StopMotor1(void);			// 停止運行一個電機
void	RunMotor1(u16 p);			// 啟動運行一個電機/******************** 主函數 **************************/
void main(void)
{M1_B_RunEn = 0;		//停止運行M1_P_DIR   = 1;	// 運行方向, 接步進電機驅動器方向輸入端(一般是光耦輸入, 低有效), 1:順時針(正轉), 0:逆時針(反轉)M1_P_PULSE = 1;	// 驅動脈沖, 低驅動, 接步進電機驅動器脈沖輸入端(一般是光耦輸入, 低有效).P1n_push_pull(0x03);	// P1.0 P1.1設置為推挽輸出PWMA_config();Timer0_Config(0, MAIN_Fosc / 1000);	//t=0: reload值是主時鐘周期數,  t=1: reload值是時間(單位us)EA = 1;UART1_config(115200UL, 2, 0);	// brt: 通信波特率,  timer=2: 波特率使用定時器2, 其它值: 使用Timer1做波特率. io=0: 串口1切換到P3.0 P3.1,  =1: 切換到P3.6 P3.7,  =2: 切換到P1.6 P1.7,  =3: 切換到P4.3 P4.4UART1_PrintString("2相步進電機細分驅動程序\r\n");UART1_PrintString("L1,500,1000   --> 馬達1以500Hz正轉1000個脈沖\r\n");UART1_PrintString("R1,500,1000   --> 馬達1以500Hz反轉1000個脈沖\r\n");UART1_PrintString("s  --> 停止所有電機\r\n");while (1){if(B_1ms)	//1ms時隙{B_1ms = 0;M1_tmp = ~M1_tmp;if(M1_B_RunEn)	//加減速處理{GetFreq1();if(M1_f1 < 100){M1_B_RunEn = 0;		//停止M1_P_DIR   = 1;	// 運行方向PWMA_CCMR1 = 0;	//禁止翻轉輸出脈沖}}if(B_RX1_OK)	//串口收到數據塊{RX1_process();	//串口數據處理B_RX1_OK = 0;RX1_Cnt = 0;}}}
}
/**********************************************/#define	UpTime	500		//加(減)速時間(ms)u16	GetStep(u16 f, u16 f_set)	//計算速度變化步進長度
{u16	i;M1_UpPulse = (u16)((u32)(f + f_set)*UpTime / 2000);	// 理論加速脈沖數if(f_set >= f)	f_set = f_set - f;		//計算頻率差else			f_set = f - f_set;		//計算頻率差i = f_set / UpTime;				// 加(減)速步進if(i == 0)	i = 1;	//步進不能為0return	i;			//返回加減速步進值
}void	StopMotor1(void)		//停止運行一個電機
{M1_f1_set  = 95;	//小于100Hz則停止 M1_f1_step = GetStep(M1_f1, M1_f1_set);
}//========== 準備好 "當前頻率M1_f1 目標頻率M1_f1_set 運行總脈沖數" 后才能啟動運行 ================= 
void	RunMotor1(u16 p)	//啟動運行一個電機, p為要運行的脈沖數
{u16	pulse;M1_f1_step = GetStep(M1_f1, M1_f1_set);	//計算步進if(p != 0)	//運行總脈沖數非0才有開始減速脈沖數{pulse = M1_UpPulse * 2;		//加減速脈沖數之和 = M1_UpPulse * 2if(p >= pulse)	pulse = M1_UpPulse;			//運行脈沖數 >= 加減速脈沖數之和, 則減速脈沖數按理論計算值else			pulse = p / 2;	//脈沖數 <  加減速脈沖數之和, 則平分脈沖pulse = p - pulse;						// 電機開始減速需要走過的脈沖數;}else	pulse = 0;EA = 0;	//臨界保護M1_PulseCnt = p;M1_DownCnt  = pulse;M1_B_RunEn  = 1;PWMA_CCMR1  = (3<<4);	//允許翻轉輸出脈沖.  通道1模式配置, 禁止預裝載. 0: 無輸出, 1:匹配時輸出高, 2:匹配時輸出低, 3:匹配時輸出翻轉.EA = 1;
}/************************************/
void		GetFreq1(void)	// 計算加減速頻率
{F0 = 0;if(M1_f1 < M1_f1_set)		//當前速度小于目標速度, 加速{F0 = 1;			//需要調速M1_f1 += M1_f1_step;if(M1_f1 > M1_f1_set)	M1_f1 = M1_f1_set;		//目標頻率已到}else if(M1_f1 > M1_f1_set)		//當前速度大于目標速度, 減速{F0 = 1;			//需要調速if(M1_f1 < M1_f1_step)	M1_f1 = 0;else				M1_f1 -= M1_f1_step;if(M1_f1 < M1_f1_set)		M1_f1 = M1_f1_set;	//目標頻率已到}if(F0)	//需要調速{M1_f1_period_set = MAIN_Fosc/2/2/M1_f1;	//PCA時鐘2T, 半周期M1_f1_update = 1;	//請求刷新}
}/**********************************************/
void RX1_process(void)			//串口1處理函數
{u8	i;u16	f, p;if(RX1_Cnt == 1){i = RX1_Buffer[0];if((i == 's') || (i == 'S'))	//大小寫均停止{StopMotor1();			//"s"   --> 停止所有電機UART1_TxByte(i);		//返回一個提示}}if((RX1_Buffer[2] == ',') && (RX1_Cnt >= 5))	//有參數{for(f=0,i=3; i<RX1_Cnt; i++)	//取頻率	"L1,500,1000"   --> 馬達1以500Hz正轉1000個脈沖{								//			"R1,500,1000"   --> 馬達1以500Hz反轉1000個脈沖if(RX1_Buffer[i] == ',')	break;		//碰到逗號結束f = f * 10 + RX1_Buffer[i] - '0';}if(RX1_Buffer[i] != ',')	f = 0;	//數據異常i++;for(p=0; i<RX1_Cnt; i++)	//取脈沖數{p = p * 10 + RX1_Buffer[i] - '0';}if(f >= 200)	//有頻率{if(RX1_Buffer[1] == '1')		//電機1{M1_f1_set  = f;				//目標頻率if(!M1_B_RunEn)	M1_f1 = 200;	//電機未啟動則從200HZ開始啟動if(RX1_Buffer[0] == 'L')	//順時針{M1_P_DIR = 1;RunMotor1(p);	//準備好 "當前頻率M1_f1 目標頻率M1_f1_set 運行總脈沖數" 后才能啟動運行UART1_TxByte('L');		//返回一個提示}if(RX1_Buffer[0] == 'R')	//逆時針{M1_P_DIR = 0;RunMotor1(p);			//準備好 "當前頻率M1_f1 目標頻率M1_f1_set 運行總脈沖數" 后才能啟動運行UART1_TxByte('R');		//返回一個提示}}}}
}//========================================================================
// 函數: void PWMA_config(void)
// 描述: PPWM配置函數。
// 參數: noe.
// 返回: none.
// 版本: V1.0, 2021-5-10
// 備注: 
//========================================================================
void PWMA_config(void)
{P_SW2 |= 0x80;		//SFR enable   PWMA_PSCR   = 1;	// 預分頻寄存器, 分頻 Fck_cnt = Fck_psc/(PSCR[15:0]+1), 邊沿對齊PWM頻率 = SYSclk/((PSCR+1)*(AAR+1)), 中央對齊PWM頻率 = SYSclk/((PSCR+1)*(AAR+1)*2).PWMA_DTR    = 0;	// 死區時間配置, n=0~127: DTR= n T,   0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,  //				0xc0 ~(0xc0+n), n=0~31: DTR=(32+n)*8T,   0xE0 ~(0xE0+n), n=0~31: DTR=(32+n)*16T,PWMA_ARR    = 0xffff;	// 自動重裝載寄存器,  控制PWM周期PWMA_CCER1  = 0;PWMA_CCER2  = 0;PWMA_SR1    = 0;PWMA_SR2    = 0;PWMA_CCMR1  = 0;PWMA_CCMR2  = 0;PWMA_CCMR3  = 0;PWMA_CCMR4  = 0;PWMA_ENO    = 0;PWMA_PS     = 0;PWMA_IER    = 0;PWMA_CCR1   = 0;			// 計數器比較值, 匹配時刻
//	PWMA_CCMR1  = (3<<4);		// 通道1模式配置, 禁止預裝載. 0: 無輸出, 1:匹配時輸出高, 2:匹配時輸出低, 3:匹配時輸出翻轉.PWMA_CCER1 |= 0x07;			// 開啟比較輸出, 低電平有效PWMA_PS    |= 0;			// 選擇IO, 0:選擇P1.0 P1.1, 1:選擇P2.0 P2.1, 2:選擇P6.0 P6.1, PWMA_ENO   |= 0x01;			// IO輸出允許,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1PPWMA_IER   |= 0x02;			// 使能中斷
/*PWMA_CCR2   = 0;			// 計數器比較值, 匹配時刻
//	PWMA_CCMR2  = (3<<4);		// 通道1模式配置, 禁止預裝載. 0: 無輸出, 1:匹配時輸出高, 2:匹配時輸出低, 3:匹配時輸出翻轉.PWMA_CCER1 |= 0x70;			// 開啟比較輸出, 低電平有效PWMA_PS    |= (0<<2);		// 選擇IO, 0:選擇P1.2 P1.3, 1:選擇P2.2 P2.3, 2:選擇P6.2 P6.3, PWMA_ENO   |= 0x04;			// IO輸出允許,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1PPWMA_IER   |= 0x04;			// 使能中斷PWMA_CCR3   = 0;			// 計數器比較值, 匹配時刻
//	PWMA_CCMR3  = (3<<4);		// 通道1模式配置, 禁止預裝載. 0: 無輸出, 1:匹配時輸出高, 2:匹配時輸出低, 3:匹配時輸出翻轉.PWMA_CCER2 |= 0x07;			// 開啟比較輸出, 低電平有效PWMA_PS    |= (0<<4);		// 選擇IO, 0:選擇P1.4 P1.5, 1:選擇P2.4 P2.5, 2:選擇P6.4 P6.5, PWMA_ENO   |= 0x10;			// IO輸出允許,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1PPWMA_IER   |= 0x08;			// 使能中斷PWMA_CCR4   = 0;			// 計數器比較值, 匹配時刻
//	PWMA_CCMR4  = (3<<4);		// 通道1模式配置, 禁止預裝載. 0: 無輸出, 1:匹配時輸出高, 2:匹配時輸出低, 3:匹配時輸出翻轉.PWMA_CCER2 |= 0x70;			// 開啟比較輸出, 低電平有效PWMA_PS    |= (0<<6);		// 選擇IO, 0:選擇P1.6 P1.7, 1:選擇P2.6 P2.7, 2:選擇P6.6 P6.7, 3:選擇P3.3 P3.4PWMA_ENO   |= 0x40;			// IO輸出允許,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1PPWMA_IER   |= 0x10;			// 使能中斷
*/M1_PWMA_ISR_En = PWMA_IER;	//設置標志允許通道1~4中斷處理PWMA_EGR    = 0x01;		//產生一次更新事件, 清除計數器和預分頻計數器, 裝載預分頻寄存器的值PWMA_BKR    = 0x80;		//主輸出使能 相當于總開關PWMA_CR1    = 0x01;		// 使能計數器, 允許自動重裝載寄存器緩沖, 邊沿對齊模式, 向上計數,  bit7=1:寫自動重裝載寄存器緩沖(本周期不會被打擾), =0:直接寫自動重裝載寄存器本(周期可能會亂掉)
}//	PWMA_PS   = (0<<6)+(0<<4)+(0<<2)+0;	//選擇IO, 4項從高到低(從左到右)對應PWM1 PWM2 PWM3 PWM4, 0:選擇P1.x, 1:選擇P2.x, 2:選擇P6.x, 
//  PWMA_PS    PWM4N PWM4P    PWM3N PWM3P    PWM2N PWM2P    PWM1N PWM1P
//    00       P1.7  P1.6     P1.5  P1.4     P1.3  P1.2     P1.1  P1.0
//    01       P2.7  P2.6     P2.5  P2.4     P2.3  P2.2     P2.1  P2.0
//    02       P6.7  P6.6     P6.5  P6.4     P6.3  P6.2     P6.1  P6.0
//    03       P3.3  P3.4      --    --       --    --       --    --//========================================================================
// 函數: void PWMA_ISR(void) interrupt PWMA_VECTOR
// 描述: PWMA中斷處理程序. 捕獲數據通過 TIM1-> CCRnH / TIM1-> CCRnL 讀取
// 參數: None
// 返回: none.
// 版本: V1.0, 2021-6-1
//========================================================================
void PWMA_ISR(void) interrupt PWMA_VECTOR
{u8	M1_sr1;
//	u8	sr2;M1_sr1 = PWMA_SR1;	//為了快速, 中斷標志用一個局部變量處理PWMA_SR1 = 0;	//清除中斷標志
//	sr2 = PWMA_SR2;	//為了快速, 中斷標志用一個局部變量處理PWMA_SR2 = 0;	//清除中斷標志M1_sr1 &= M1_PWMA_ISR_En;	//每個通道可以單獨允許中斷處理if(M1_sr1 & 0x02)	//通道1中斷標志{if(M1_B_RunEn)	//電機運行中{if(M1_f1_update)	//刷新頻率值{M1_f1_update = 0;M1_f1_period = M1_f1_period_set;}M1_CCAP1_tmp += M1_f1_period;PWMA_CCR1  = M1_CCAP1_tmp;	// 計數器比較值, 匹配時刻if(M1_P_PULSE)	//產生了完整的一個脈沖{if(M1_PulseCnt != 0)	// 脈沖數未完成{if(--M1_PulseCnt == 0)	//若 脈沖數-1 == 0{M1_B_RunEn = 0;		// 關停電機M1_P_DIR   = 1;		// 轉向光耦關閉PWMA_CCMR1 = 0;		//禁止取反輸出脈沖}}if(M1_DownCnt != 0)		// 減速脈沖未完{if(--M1_DownCnt == 0)	M1_f1_set = 200;	//設置目標頻率, 開始減速}}}else  M1_P_PULSE = 1;}
/*if(M1_sr1 & 0x04)	//通道2中斷標志{CCAP2_tmp += f2_period;PWMA_CCR2  = CCAP2_tmp;	// 計數器比較值, 匹配時刻}if(M1_sr1 & 0x08)	//通道3中斷標志{CCAP3_tmp += f3_period;PWMA_CCR3  = CCAP3_tmp;	// 計數器比較值, 匹配時刻}if(M1_sr1 & 0x10)	//通道4中斷標志{CCAP4_tmp += f4_period;PWMA_CCR4  = CCAP4_tmp;	// 計數器比較值, 匹配時刻}
*/
}//========================================================================
// 函數:u8	Timer0_Config(u8 t, u32 reload)
// 描述: timer0初始化函數.
// 參數:      t: 重裝值類型, 0表示重裝的是系統時鐘數, 其余值表示重裝的是時間(us).
//       reload: 重裝值.
// 返回: 0: 初始化正確, 1: 重裝值過大, 初始化錯誤.
// 版本: V1.0, 2018-12-20
//========================================================================
u8	Timer0_Config(u8 t, u32 reload)	//t=0: reload值是主時鐘周期數,  t=1: reload值是時間(單位us)
{TR0 = 0;	//停止計數if(t != 0)	reload = (u32)(((float)MAIN_Fosc * (float)reload)/1000000UL);	//重裝的是時間(us), 計算所需要的系統時鐘數.if(reload >= (65536UL * 12))	return 1;	//值過大, 返回錯誤if(reload < 65536UL)	AUXR |= 0x80;		//1T modeelse{AUXR &= ~0x80;	//12T modereload = reload / 12;}reload = 65536UL - reload;TH0 = (u8)(reload >> 8);TL0 = (u8)(reload);ET0 = 1;	//允許中斷TMOD = (TMOD & ~0x03) | 0;	//工作模式, 0: 16位自動重裝, 1: 16位定時/計數, 2: 8位自動重裝, 3: 16位自動重裝, 不可屏蔽中斷TR0 = 1;	//開始運行return 0;
}//========================================================================
// 函數: void timer0_ISR(void) interrupt TIMER0_VECTOR
// 描述:  timer0中斷函數.
// 參數: none.
// 返回: none.
// 版本: V1.0, 2018-12-20
//========================================================================
void timer0_ISR(void) interrupt TIMER0_VECTOR
{B_1ms = 1;	//標志1ms時隙if(RX1_TimerOut != 0)		//串口接收超時處理{if(--RX1_TimerOut == 0){if(RX1_Cnt != 0)	B_RX1_OK = 1;	//接收到一塊數據}}
}//========================================================================
// 函數: SetTimer2Baudraye(u16 dat)
// 描述: 設置Timer2做波特率發生器。
// 參數: dat: Timer2的重裝值.
// 返回: none.
// 版本: VER1.0
// 日期: 2018-4-2
// 備注: 
//========================================================================
void	SetTimer2Baudraye(u16 dat)	// 選擇波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
{AUXR &= ~(1<<4);	//Timer stopAUXR &= ~(1<<3);	//Timer2 set As TimerAUXR |=  (1<<2);	//Timer2 set as 1T modeTH2 = (u8)(dat >> 8);TL2 = (u8)dat;IE2  &= ~(1<<2);	//禁止中斷AUXR |=  (1<<4);	//Timer run enable
}//========================================================================
// 函數: void	UART1_config(u32 brt, u8 timer, u8 io)
// 描述: UART1初始化函數。
// 參數:   brt: 通信波特率.
//       timer: 波特率使用的定時器, timer=2: 波特率使用定時器2, 其它值: 使用Timer1做波特率.
//          io: 串口1切換到的IO,  io=1: 串口1切換到P3.0 P3.1,  =1: 切換到P3.6 P3.7,  =2: 切換到P1.6 P1.7,  =3: 切換到P4.3 P4.4
// 返回: none.
// 版本: VER1.0
// 日期: 2018-4-2
// 備注: 
//========================================================================
void	UART1_config(u32 brt, u8 timer, u8 io)	// brt: 通信波特率,  timer=2: 波特率使用定時器2, 其它值: 使用Timer1做波特率. io=0: 串口1切換到P3.0 P3.1,  =1: 切換到P3.6 P3.7,  =3: 切換到P4.3 P4.4
{brt = 65536UL - (MAIN_Fosc / 4) / brt;if(timer == 2)	//波特率使用定時器2{AUXR |= 0x01;		//S1 BRT Use Timer2;SetTimer2Baudraye((u16)brt);}else		//波特率使用定時器1{TR1 = 0;AUXR &= ~0x01;		//S1 BRT Use Timer1;AUXR |=  (1<<6);	//Timer1 set as 1T modeTMOD &= ~(1<<6);	//Timer1 set As TimerTMOD &= ~0x30;		//Timer1_16bitAutoReload;TH1 = (u8)(brt >> 8);TL1 = (u8)brt;ET1 = 0;			// 禁止Timer1中斷INT_CLKO &= ~0x02;	// Timer1不輸出高速時鐘TR1  = 1;			// 運行Timer1}if(io == 1)	{S1_USE_P36P37();	P3n_standard(0xc0);}	//切換到 P3.6 P3.7else if(io == 2)	{S1_USE_P16P17();	P1n_standard(0xc0);}	//切換到 P1.6 P1.7else if(io == 3)	{S1_USE_P43P44();	P4n_standard(0x18);}	//切換到 P4.3 P4.4else				{S1_USE_P30P31();	P3n_standard(0x03);}	//切換到 P3.0 P3.1SCON = (SCON & 0x3f) | (1<<6);	// 8位數據, 1位起始位, 1位停止位, 無校驗ES  = 1;	//允許中斷REN = 1;	//允許接收
}//========================================================================
// 函數: void UART1_PrintString(u8 *puts)
// 描述: 串口1字符串打印函數
// 參數: puts: 字符串指針.
// 返回: none.
// 版本: VER1.0
// 日期: 2018-4-2
// 備注: 
//========================================================================
void UART1_PrintString(u8 *puts)
{for (; *puts != 0;	puts++){B_TX1_Busy = 1;		//標志發送忙SBUF = *puts;		//發一個字節while(B_TX1_Busy);	//等待發送完成}
}void UART1_TxByte(u8 dat)	//串口1發送一個字節
{B_TX1_Busy = 1;		//標志發送忙SBUF = dat;			//發一個字節while(B_TX1_Busy);	//等待發送完成
}//========================================================================
// 函數: void UART1_ISR(void) interrupt UART1_VECTOR
// 描述: 串口1中斷函數
// 參數: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2018-4-2
// 備注: 
//========================================================================
void UART1_ISR(void) interrupt UART1_VECTOR
{if(RI){RI = 0;if(!B_RX1_OK){if(RX1_Cnt >= RX1_LENGTH)		RX1_Cnt = 0;RX1_Buffer[RX1_Cnt++] = SBUF;RX1_TimerOut = 5;}}if(TI){TI = 0;B_TX1_Busy = 0;}
}

稍微改寫梁工的代碼應用到具體實際的單片機引腳,主要的 第一難點 在于PWMB_config的配置到對應的P2.3引腳上輸出PWMB,這里有切換引腳的寄存器。第二難點 在于(PWMB_CCRx)的比較值 一定要選對,不然比較個啥?這里是P2.3引腳在PWMB模塊上,在PWMB_CCR8 捕獲/比較寄存器里面。

代碼如下:

Step_Motor2.c文件


/*------------------------------------------------------------------*/
/* --- STC MCU International Limited -------------------------------*/
/* --- STC 1T Series MCU Demo --------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ---------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ---------------------*/
/* --- Web: www.stcai.com ------------------------------------------*/
/* --- BBS: www.stcaimcu.com ---------------------------------------*/
/* If you want to use the program or the program referenced in the  */
/* article, please specify in which data and procedures from STC    */
/*------------------------------------------------------------------*/#include	"APP.h"
#include 	"Step_Motor2.h"
#include 	"Step_Motor1.h"
#include	"STC8H_PWM.h"
#include	"STC8G_H_GPIO.h"
#include	"STC8G_H_NVIC.h"/*************	功能說明	**************用高級PWMB匹配取反輸出脈沖控制步進電機驅動器.
調用托盤運動******************************************//*************	本地常量聲明	**************/
#define motor2_StopThreshold 40//電機停止閾值/*************	本地變量聲明	**************/u16	M2_CCAP1_tmp;
u8	M2_PWMB_ISR_En;	//每個通道可以單獨允許中斷處理, bit4:通道4, bit3:通道3, bit2:通道2, bit1:通道1.//================== 步進電機相關變量定義 ===================bit		M2_B_RunEn;					//運行允許
bit		M2_f1_update;				//請求刷新頻率值
u16		M2_f1_period;				//當前頻率對應的周期(半周期)(中斷使用, 應用層不可操作)
u16		M2_f1_period_set;		//需要刷新的目標頻率對應的周期(半周期)
u16		M2_f1;							//當前頻率
u16		M2_f1_set;					//目標頻率
u16		M2_f1_step;					//加減速頻率變化的步長
u16		M2_UpPulse;					//加(減)速脈沖數
u16		M2_PulseCnt;				//電機運行總脈沖數, 為0則連續運行
u16		M2_DownCnt;					//運行到要減速輸出的脈沖數
u16		M2_UpTime;					//加(減)速時間(ms)
u16 	M2_Pulse_counter;		//脈沖計數器
//===========================================================void Motor2_clearZero(void)
{M2_f1_period = 0;			//當前頻率對應的周期(半周期)(中斷使用, 應用層不可操作)M2_f1_period_set = 0;	//需要刷新的目標頻率對應的周期(半周期)M2_f1 = 0;						//當前頻率M2_f1_set = 0;				//目標頻率M2_f1_step = 0;				//加減速頻率變化的步長M2_UpTime = 0;				//加(減)速時間(ms)M2_PulseCnt = 0;			//電機運行總脈沖數, 為0則連續運行M2_DownCnt = 0;				//運行到要減速輸出的脈沖數M2_UpPulse = 0;				//加(減)速脈沖數
}/******************** 主函數 **************************/
void Motor2_Init(void)
{
//	lightSource_PWM = 1;PWMB_phase = YAXIS_MOTOR;M2_B_RunEn = 0;		//停止運行M2_P_DIR   = 1;	// 運行方向, 接步進電機驅動器方向輸入端(一般是光耦輸入, 低有效), 1:順時針(正轉), 0:逆時針(反轉)M2_P_PULSE = 1;	// 驅動脈沖, 低驅動, 接步進電機驅動器脈沖輸入端(一般是光耦輸入, 低有效).
//	P1_MODE_OUT_PP(GPIO_Pin_1 | GPIO_Pin_0);//P2.1 驅動器PWMM2_PWMB_config();}void Sample_Motor6(void)
{M2_f1_set  = 5000;M2_f1 = 200;	//電機未啟動則從200HZ開始啟動RunMotor2(3200);
}void Sample_Motor2(void)
{if(M2_B_RunEn)	//加減速處理{GetFreq2();if(M2_f1 < motor2_StopThreshold){M2_B_RunEn = 0;		//停止PWMB_CCMR4 = 0;	//禁止翻轉輸出脈沖Pallet_status = 0;}}
}/**********************************************/u16	M2_GetStep(u16 f, u16 f_set)	//計算速度變化步進長度
{u16	i;M2_UpPulse = (u16)((u32)(f + f_set)*M2_UpTime / 2000);	// 理論加速脈沖數if(f_set >= f)	f_set = f_set - f;		//計算頻率差else			f_set = f - f_set;		//計算頻率差i = f_set / M2_UpTime;				// 加(減)速步進if(i == 0)	i = 1;	//步進不能為0return	i;			//返回加減速步進值
}void	StopMotor2(void)		//停止運行一個電機
{M2_f1_set  = motor2_StopThreshold;	//小于100Hz則停止 M2_f1_step = M2_GetStep(M2_f1, M2_f1_set);
}void	E_StopMotor2(void)		//停止運行一個電機
{M2_f1_set  = motor2_StopThreshold;	//小于100Hz則停止 M2_f1 = 200;Pallet_status = 0;M2_f1_step = M2_GetStep(M2_f1, M2_f1_set);
}void	Emergency_StopMotor2(void)		//停止運行一個電機
{M2_f1_set  = motor2_StopThreshold;	//小于100Hz則停止 M2_f1 = 0;Pallet_status = 0;M2_B_RunEn = 0;		//停止PWMB_CCMR4 = 0;		//禁止翻轉輸出脈沖
}//========== 準備好 "當前頻率M2_f1 目標頻率M2_f1_set 運行總脈沖數" 后才能啟動運行 ================= 
void	RunMotor2(u16 p)	//啟動運行一個電機, p為要運行的脈沖數
{u16	pulse;M2_f1_step = M2_GetStep(M2_f1, M2_f1_set);	//計算步進if(p != 0)	//運行總脈沖數非0才有開始減速脈沖數{pulse = M2_UpPulse * 2;		//加減速脈沖數之和 = M2_UpPulse * 2if(p >= pulse)	pulse = M2_UpPulse;			//運行脈沖數 >= 加減速脈沖數之和, 則減速脈沖數按理論計算值else			pulse = p / 2;	//脈沖數 <  加減速脈沖數之和, 則平分脈沖pulse = p - pulse;						// 電機開始減速需要走過的脈沖數;}else	pulse = 0;EA = 0;	//臨界保護M2_PulseCnt = p;M2_DownCnt  = pulse;M2_B_RunEn  = 1;PWMB_CCMR4  = (3<<4);	//允許翻轉輸出脈沖.  通道1模式配置, 禁止預裝載. 0: 無輸出, 1:匹配時輸出高, 2:匹配時輸出低, 3:匹配時輸出翻轉.EA = 1;
}/************************************/
void	GetFreq2(void)	// 計算加減速頻率
{F0 = 0;//內部寄存器if(M2_f1 < M2_f1_set)		//當前速度小于目標速度, 加速{F0 = 1;			//需要調速M2_f1 += M2_f1_step;if(M2_f1 > M2_f1_set)	M2_f1 = M2_f1_set;		//目標頻率已到}else if(M2_f1 > M2_f1_set)		//當前速度大于目標速度, 減速{F0 = 1;			//需要調速if(M2_f1 < M2_f1_step)	M2_f1 = 0;else				M2_f1 -= M2_f1_step;if(M2_f1 < M2_f1_set)		M2_f1 = M2_f1_set;	//目標頻率已到}if(F0)	//需要調速{M2_f1_period_set = MAIN_Fosc/2/2/M2_f1;	//PCA時鐘2T, 半周期M2_f1_update = 1;	//請求刷新}
}/**********************************************///========================================================================
// 函數: void M2_PWMB_config(void)
// 描述: PPWM配置函數。
// 參數: noe.
// 返回: none.
// 版本: V1.0, 2021-5-10
// 備注: 
//========================================================================
void M2_PWMB_config(void)
{PWMx_InitDefine		PWMx_InitStructure;NVIC_PWM_Init(PWMB,ENABLE,Priority_3);P_SW2 |= 0x80;		//SFR enable   PWMB_PSCR   = 1;	// 預分頻寄存器, 分頻 Fck_cnt = Fck_psc/(PSCR[15:0]+1), 邊沿對齊PWM頻率 = SYSclk/((PSCR+1)*(AAR+1)), 中央對齊PWM頻率 = SYSclk/((PSCR+1)*(AAR+1)*2).PWMB_DTR    = 0;	// 死區時間配置, n=0~127: DTR= n T,   0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,  //				0xc0 ~(0xc0+n), n=0~31: DTR=(32+n)*8T,   0xE0 ~(0xE0+n), n=0~31: DTR=(32+n)*16T,PWMB_ARR    = 0xffff;	// 自動重裝載寄存器,  控制PWM周期PWMB_CCER1  = 0;PWMB_CCER2  = 0;PWMB_SR1    = 0;PWMB_SR2    = 0;PWMB_CCMR1  = 0;PWMB_CCMR2  = 0;PWMB_CCMR3  = 0;PWMB_CCMR4  = 0;PWMB_ENO    = 0;PWMB_PS     = 0;PWMB_IER    = 0;PWMB_CCR8   = 5000;		// 比較值, 控制占空比(高電平時鐘數)PWMB_CCER2 |= 0x30;		// 開啟比較輸出, 高電平有效PWMB_PS    |= (0<<6);	// 選擇IO, 0:選擇P2.3, 1:選擇P3.4, 2:選擇P0.3, 3:選擇P7.7, PWMB_ENO   |= 0x40;		// IO輸出允許,  bit6: ENO8P, bit4: ENO7P,  bit2: ENO6P,  bit0: ENO5PPWMB_IER   |= 0x30;		// 使能中斷PWMB_EGR    = 0x01;		//產生一次更新事件, 清除計數器和預分頻計數器, 裝載預分頻寄存器的值PWMB_BKR    = 0x80;		// 主輸出使能 相當于總開關PWMB_CR1    = 0x01;		// 使能計數器, 允許自動重裝載寄存器緩沖, 邊沿對齊模式, 向上計數,  bit7=1:寫自動重裝載寄存器緩沖(本周期不會被打擾), =0:直接寫自動重裝載寄存器本(周期可能會亂掉)}//========================================================================
// 函數: void PWMB_ISR(void) interrupt PWMB_VECTOR
// 描述: PWMB中斷處理程序. 捕獲數據通過 TIM2-> CCRnH / TIM2-> CCRnL 讀取
// 參數: None
// 返回: none.
// 版本: V1.0, 2021-6-1
//========================================================================
void PWMB_ISR(void) interrupt PWMB_VECTOR
{u8	M2_sr1;
//	u8	sr2;M2_sr1 = PWMB_SR1;	//為了快速, 中斷標志用一個局部變量處理PWMB_SR1 = 0;	//清除中斷標志
//	sr2 = PWMB_SR2;	//為了快速, 中斷標志用一個局部變量處理PWMB_SR2 = 0;	//清除中斷標志M2_sr1 &= M2_PWMB_ISR_En;	//每個通道可以單獨允許中斷處理//	PWMB_CCR8   = 500;
//	if(M2_sr1 & 0x02)	//通道1中斷標志{if(M2_B_RunEn)	//電機運行中{if(M2_f1_update)	//刷新頻率值{M2_f1_update = 0;M2_f1_period = M2_f1_period_set;}M2_CCAP1_tmp += M2_f1_period;
//			PWMB_CCR5  = M2_CCAP1_tmp;	// 計數器比較值, 匹配時刻PWMB_CCR8  = M2_CCAP1_tmp;	// 計數器比較值, 匹配時刻if(M2_P_PULSE)	//產生了完整的一個脈沖{if(!M2_P_DIR)M2_Pulse_counter++;elseM2_Pulse_counter--;				if(M2_PulseCnt != 0)	// 脈沖數未完成{if(--M2_PulseCnt == 0)	//若 脈沖數-1 == 0{M2_B_RunEn = 0;		// 關停電機M2_P_DIR   = 1;		// 轉向光耦關閉PWMB_CCMR4 = 0;		//禁止取反輸出脈沖Pallet_status = 0;}}if(M2_DownCnt != 0)		// 減速脈沖未完{if(--M2_DownCnt == 0)	M2_f1_set = 200;	//設置目標頻率, 開始減速}}}else  M2_P_PULSE = 1;}
}

Step_ Motor2.h文件

/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com  -----------------------------------------*/
/* --- QQ:  800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代碼,請在程序中注明使用了STC的資料及程序            */
/*---------------------------------------------------------------------*/#ifndef __STEP_MOTOR2_H_
#define __STEP_MOTOR2_H_#include "config.h"
#include	"APP.h"
#include	"APP_Task.h"#define M2_P_DIR_PORT P4
#define M2_P_DIR_BIT 4
//sbit	M2_P_DIR   = P1^6;	// 裸板測試
sbit	M2_P_DIR   = P4^4;	// 運行方向, 接步進電機驅動器方向輸入端(一般是光耦輸入, 低有效), 1:順時針(正轉), 0:逆時針(反轉)
sbit	M2_P_PULSE = P2^3;	// 驅動脈沖, 低驅動, 接步進電機驅動器脈沖輸入端(一般是光耦輸入, 低有效).
sbit	M2_EN = P4^2;				// 驅動器使能端extern bit		M2_B_RunEn;				//運行允許
extern bit		M2_f1_update;			//請求刷新頻率值
extern u16		M2_f1_period;			//當前頻率對應的周期(半周期)(中斷使用, 應用層不可操作)
extern u16		M2_f1_period_set;	//需要刷新的目標頻率對應的周期(半周期)
extern u16		M2_f1;							//當前頻率
extern u16		M2_f1_set;					//目標頻率
extern u16		M2_f1_step;				//加減速頻率變化的步長
extern u16		M2_UpPulse;		//加(減)速脈沖數
extern u16		M2_PulseCnt;	//電機運行總脈沖數, 為0則連續運行
extern u16		M2_DownCnt;		//運行到要減速輸出的脈沖數
extern u16		M2_UpTime;			//加(減)速時間(ms)
extern u16 		M2_Pulse_counter;		//脈沖計數器extern u8 Pallet_status;
/*************	本地函數聲明	**************/void 	M2_PWMB_config(void);
u16		GetStep(u16 f, u16 f_set);	// 計算速度變化步進長度
void	GetFreq2(void);				// 計算加減速頻率
void	StopMotor2(void);			// 停止運行一個電機
void	RunMotor2(u16 p);			// 啟動運行一個電機
void Sample_Motor2(void);void Sample_Motor6(void);
void	E_StopMotor2(void);		//停止運行一個電機
void	Emergency_StopMotor2(void);		//停止運行一個電機#endif

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/82968.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/82968.shtml
英文地址,請注明出處:http://en.pswp.cn/web/82968.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python高階函數:從入門到精通

目錄 Python高階函數詳解&#xff1a;從概念到高級應用引言&#xff1a;函數式編程的魅力一、高階函數基礎概念1.1 什么是高階函數1.2 Python中的一等函數 二、內置高階函數詳解2.1 map函數&#xff1a;數據轉換利器2.2 filter函數&#xff1a;數據篩選專家2.3 reduce函數&…

騰訊開源視頻生成工具 HunyuanVideo-Avatar,上傳一張圖+一段音頻,就能讓圖中的人物、動物甚至虛擬角色“活”過來,開口說話、唱歌、演相聲!

騰訊混元團隊提出的 HunyuanVideo-Avatar 是一個基于多模態擴散變換器&#xff08;MM-DiT&#xff09;的模型&#xff0c;能夠生成動態、情緒可控和多角色對話視頻。支持僅 10GB VRAM 的單 GPU運行&#xff0c;支持多種下游任務和應用。例如生成會說話的虛擬形象視頻&#xff0…

DeepSeek-R1-0528:開源推理模型的革新與突破

一、 發布日期與背景 2025年5月29日&#xff0c;備受業界關注的DeepSeek推理模型DeepSeek-R1迎來重要更新——DeepSeek-R1-0528模型正式發布。此次更新采取了“靜默發布”策略&#xff0c;未提前預告&#xff0c;而是通過官方渠道&#xff08;官網、App、小程序&#xff09;及…

LeetCode 1723: 完成所有工作的最短時間

給你一個整數數組 jobs &#xff0c;其中 jobs[i] 是完成第 i 項工作要花費的時間。 請你將這些工作分配給 k 位工人。所有工作都應該分配給工人&#xff0c;且每項工作只能分配給一位工人。工人的 工作時間 是完成分配給他們的所有工作花費時間的總和。請你設計一套最佳的工作…

JDK8新特性之Steam流

這里寫目錄標題 一、Stream流概述1.1、傳統寫法1.2、Stream寫法1.3、Stream流操作分類 二、Stream流獲取方式2.1、根據Collection獲取2.2、通過Stream的of方法 三、Stream常用方法介紹3.1、forEach3.2、count3.3、filter3.4、limit3.5、skip3.6、map3.7、sorted3.8、distinct3.…

split方法

在編程中&#xff0c;split 方法通常用于將字符串按照指定的分隔符拆分成多個部分&#xff0c;并返回一個包含拆分結果的列表&#xff08;或數組&#xff09;。不同編程語言中的 split 方法語法略有不同&#xff0c;但核心功能相似。以下是常見語言中的用法&#xff1a; ?1. P…

深入理解 x86 匯編中的符號擴展指令:從 CBW 到 CDQ 的全解析

引入 在匯編語言的世界里&#xff0c;數據寬度的轉換是一項基礎卻至關重要的操作。尤其是在處理有符號數時&#xff0c;符號擴展&#xff08;Sign Extension&#xff09;作為保持數值符號一致性的核心技術&#xff0c;直接影響著運算結果的正確性。本文將聚焦 x86 架構中最常用…

計算機基礎知識(第五篇)

計算機基礎知識&#xff08;第五篇&#xff09; 架構演化與維護 軟件架構的演化和定義 軟件架構的演化和維護就是對架構進行修改和完善的過程&#xff0c;目的就是為了使軟件能夠適應環境的變化而進行的糾錯性修改和完善性修改等&#xff0c;是一個不斷迭代的過程&#xff0…

前端開發三劍客:HTML5+CSS3+ES6

在前端開發領域&#xff0c;HTML、CSS和JavaScript構成了構建網頁與Web應用的核心基礎。隨著技術標準的不斷演進&#xff0c;HTML5、CSS3以及ES6&#xff08;ECMAScript 2015及后續版本&#xff09;帶來了諸多新特性與語法優化&#xff0c;極大地提升了開發效率和用戶體驗。本文…

c++ 頭文件

目錄 防止頭文件重復包含 頭文件的作用 如何讓程序的多個 .cpp 文件之間共享全局變量&#xff08;可能是 int、結構體、數組、指針、類對象&#xff09;? 防止頭文件重復包含 為什么要防止頭問件重復包含&#xff1f; 當然一般也不會把變量定義放到頭問件&#xff0c;那為…

深入解析 JavaScript 中 var、let、const 的核心區別與實踐應用

一、歷史背景與語法基礎 JavaScript 作為動態弱類型語言&#xff0c;變量聲明機制經歷了從 ES5 到 ES6 的重大變革。在 ES5 及更早版本中&#xff0c;var 是唯一的變量聲明方式&#xff0c;而 ES6&#xff08;2015 年&#xff09;引入了 let 和 const&#xff0c;旨在解決 var…

【Linux庖丁解牛】—自定義shell的編寫!

1. 打印命令行提示符 在我們使用系統提供的shell時&#xff0c;每次都會打印出一行字符串&#xff0c;這其實就是命令行提示符&#xff0c;那我們自定義的shell當然也需要這一行字符串。 這一行字符串包含用戶名&#xff0c;主機名&#xff0c;當前工作路徑&#xff0c;所以&a…

應用案例 | 設備分布廣, 現場維護難? 宏集Cogent DataHub助力分布式鍋爐遠程運維, 讓現場變“透明”

在日本&#xff0c;能源利用與環保問題再次成為社會關注的焦點。越來越多的工業用戶開始尋求更高效、可持續的方式來運營設備、管理能源。而作為一家專注于節能與自動化系統集成的企業&#xff0c;日本大阪的TESS工程公司給出了一個值得借鑒的答案。 01 鍋爐遠程監控難題如何破…

【OSG學習筆記】Day 16: 骨骼動畫與蒙皮(osgAnimation)

骨骼動畫基礎 骨骼動畫是 3D 計算機圖形中常用的技術&#xff0c;它通過以下兩個主要組件實現角色動畫。 骨骼系統 (Skeleton)&#xff1a;由層級結構的骨頭組成&#xff0c;類似于人體骨骼蒙皮 (Mesh Skinning)&#xff1a;將模型網格頂點綁定到骨骼上&#xff0c;使骨骼移動…

jdk同時安裝多個版本并自由切換

一、安裝不同版本的JDK 二、配置環境變量&#xff08;多版本JDK&#xff09; 1. 新建版本專用環境變量&#xff08;用于切換&#xff09; 操作位置&#xff1a;系統變量 > 新建 變量名&#xff1a;JAVA_HOME_1.8 變量值&#xff1a;JDK 8安裝路徑變量名&#xff1a;JAVA1…

java中裝飾模式

目錄 一 裝飾模式案例說明 1.1 說明 1.2 代碼 1.2.1 定義數據服務接口 1.2.2 定義基礎數據庫服務實現 1.2.3 日志裝飾器 1.2.4 緩存裝飾器 1.2.5 主程序調用 1.3 裝飾模式的特點 一 裝飾模式案例說明 1.1 說明 本案例是&#xff1a;數據查詢增加緩存&#xff0c;使用…

【論文閱讀】YOLOv8在單目下視多車目標檢測中的應用

Application of YOLOv8 in monocular downward multiple Car Target detection????? 原文真離譜&#xff0c;文章都不全還發上來 引言 自動駕駛技術是21世紀最重要的技術發展之一&#xff0c;有望徹底改變交通安全和效率。任何自動駕駛系統的核心都依賴于通過精確物體檢…

在uni-app中如何從Options API遷移到Composition API?

uni-app 從 Options API 遷移到 Composition API 的詳細指南 一、遷移前的準備 升級環境&#xff1a; 確保 HBuilderX 版本 ≥ 3.2.0項目 uni-app 版本 ≥ 3.0.0 了解 Composition API 基礎&#xff1a; 響應式系統&#xff1a;ref、reactive生命周期鉤子&#xff1a;onMount…

408第一季 - 數據結構 - 圖

圖的概念 完全圖 無向圖的完全圖可以這么想&#xff1a;如果有4個點&#xff0c;每個點都會連向3個點&#xff0c;每個點也都會有來回的邊&#xff0c;所以除以2 有向圖就不用除以2 連通分量 不多解釋 極大連通子圖的意思就是讓你把所有連起來的都圈出來 強連通圖和強連通…

31.2linux中Regmap的API驅動icm20608實驗(編程)_csdn

regmap 框架就講解就是上一個文章&#xff0c;接下來學習編寫的 icm20608 驅動改為 regmap 框架。 icm20608 驅動我們在之前的文章就已經編寫了&#xff01; 因為之前已經對icm20608的設備樹進行了修改&#xff0c;所以大家可以看到之前的文章&#xff01;當然這里我們還是帶領…