版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第第頁(yè)無(wú)刷電機(jī)小車(chē)開(kāi)發(fā)記錄—PWM信號(hào)輸入捕獲驅(qū)動(dòng)
之前是完成了BSP的移植和導(dǎo)入,接下來(lái)就要嘗試移植FOC(算法)了,開(kāi)源的FOC算法也比較多,我這里打算利用(Sim)pleFOC進(jìn)行移植。本身的SimpleFOC是基于(C++)的,這里要移植成C代碼。另外,SimpleFOC的(SD)K其中已經(jīng)適配了很多種類(lèi)的(傳感器),(驅(qū)動(dòng)器)以及(無(wú)刷電機(jī))。如果(硬件)使用的是它已經(jīng)適配的方案,則只需要簡(jiǎn)單配置一下就可以驅(qū)動(dòng)了。
而我這里是要在(RTThread)下移植FOC,更傾向于使用RTThread的框架,所以各種傳感器和驅(qū)動(dòng)器的適配計(jì)劃加到RTThread的驅(qū)動(dòng)這邊來(lái)做。FOC那邊只移植SimpleFOC的核心算法即可。所以在正式移植FOC算法之前,還需要先搭建用到的底層驅(qū)動(dòng)。
今天就先整理一下讀取磁編碼器PWM(信號(hào))的輸入捕獲驅(qū)動(dòng)的移植記錄。其實(shí)某些適配更好的BSP內(nèi)的RTThread驅(qū)動(dòng)庫(kù)里面已經(jīng)有了輸入捕獲驅(qū)動(dòng),但只是捕獲了輸入脈寬的時(shí)間,而我這里需要的是捕獲PWM信號(hào)的占空比,也就對(duì)應(yīng)了磁編碼器探測(cè)到的(電機(jī))位置。但大體功能類(lèi)似,所以隨便找一個(gè)類(lèi)似的底層驅(qū)動(dòng)進(jìn)行一下修改和移植即可。
磁編碼器簡(jiǎn)介
我這里用的是賽卓(電子)的國(guó)產(chǎn)磁編碼器(芯片)SC60228,詳情請(qǐng)看其數(shù)據(jù)手冊(cè),主要特性如下:
移植RTT驅(qū)動(dòng)
這個(gè)比較簡(jiǎn)單,因?yàn)镽TT驅(qū)動(dòng)庫(kù)內(nèi)已經(jīng)有了“rt_inputcapture.c”的驅(qū)動(dòng)文件,在SDK的“(rt-thread)/components/drivers/misc”目錄下。只不過(guò)大多數(shù)的BSP沒(méi)有做對(duì)應(yīng)的適配而已。那先不管BSP那邊的適配問(wèn)題,先把這個(gè)C文件和對(duì)應(yīng)的頭文件拷貝一份,比如我重命名為“PWM_input_capture.c”和“PWM_input_capture.h”。
然后代碼內(nèi)容改動(dòng)不大,主要改的是返回的數(shù)據(jù)除了脈寬時(shí)間還有一個(gè)周期時(shí)間,這樣就可以計(jì)算輸入PWM信號(hào)的占空比了。另外,原有的驅(qū)動(dòng)上使用的是ringbuffer做了一個(gè)數(shù)據(jù)緩存,這樣數(shù)據(jù)處理可以異步話,什么時(shí)候需要什么時(shí)候把緩存內(nèi)的數(shù)據(jù)全部讀走即可。但各人考慮,我應(yīng)用的場(chǎng)合是用這個(gè)信號(hào)來(lái)驅(qū)動(dòng)無(wú)刷電機(jī),這個(gè)PWM信號(hào)的輸入頻率也才1Khz,市面上大多數(shù)的無(wú)刷電機(jī)驅(qū)動(dòng),底層控制頻率基本都達(dá)到了10Khz以上。
所以我這里肯定不需要異步處理的,會(huì)直接用這個(gè)信號(hào)觸發(fā)底層控制。而且控制效果還需要測(cè)試,如果轉(zhuǎn)速上不去或者抖動(dòng)厲害的話,可能還需要想辦法插值細(xì)化或者改用SPI讀?。ň幋a器)數(shù)據(jù)(這也是為什么硬件上做了兩種(接口)的原因,就是想去測(cè)試探索一些好玩的東西)。所以我這里是直接去掉了ringbuffer,加入了信號(hào)量。到時(shí)候上層開(kāi)一個(gè)線程去等待這個(gè)信號(hào)量去跑FOC算法。頭文件修改如下:
structpwm_inputcapture_data
{
rt_uint32_tpulsewidth_us;//脈寬
rt_uint32_tpulsecycle_us;//周期
};
structpwm_inputcapture_device
{
structrt_deviceparent;
conststructpwm_inputcapture_opsops;
rt_sem_tsem;
structpwm_inputcapture_datapulse_pa(ram);
};
/
captureoperators
*/
structpwm_inputcapture_ops
{
rt_err_t(*init)(structpwm_inputcapture_device*inputcapture);
rt_err_t(*open)(structpwm_inputcapture_device*inputcapture);
rt_err_t(*close)(structpwm_inputcapture_device*inputcapture);
};
voidpwm_hw_inputcapture_isr(structpwm_inputcapture_device*inputcapture);
rt_err_trt_device_pwm_inputcapture_register(structpwm_inputcapture_device*inputcapture,
constchar*name,
void*data);
C文件主要修改的是回調(diào)函數(shù),把之前的數(shù)據(jù)加入ringbuffer的操作改成了釋放信號(hào)量,其它地方的修改都是一些簡(jiǎn)單的適配,由于C代碼較多,我這里就不都貼出來(lái)了,相信大家肯定會(huì)自己完成適配,甚至比我的還要適配的好。而我的代碼,等我第一期的功能開(kāi)發(fā)完了,會(huì)整體開(kāi)源出來(lái)。C代碼主要修改的回調(diào)函數(shù)如下:
voidrt_hw_pwm_inputcapture_isr(structpwm_inputcapture_device*inputcapture)
{
rt_sem_release(inputcapture->sem);
if(inputcapture->parent.rx_indica(te)!=RT_NULL)
inputcapture->parent.rx_indicate(
}
適配BSP驅(qū)動(dòng)
BSP驅(qū)動(dòng)的適配稍微麻煩一點(diǎn),如果大家能找到其它類(lèi)似BSP內(nèi)的相似驅(qū)動(dòng)可以進(jìn)行移植,那我這里簡(jiǎn)單找了一下并沒(méi)有找到,所以仿照RTT的驅(qū)動(dòng)適配方式,自己適配了一下。主要實(shí)現(xiàn)要點(diǎn)就是開(kāi)啟每個(gè)(Ti)mer的CH0和CH1雙通道對(duì)CI0或者CI1輸入的PWM信號(hào)進(jìn)行采樣,一個(gè)捕獲脈寬,一個(gè)捕獲周期,從而得到占空比。剩下的就是一些向下調(diào)用(GD32)的驅(qū)動(dòng)庫(kù)A(PI),向上適配RTT的驅(qū)動(dòng)接口。同樣,下面只給出主要的初始化代碼和中斷處理代碼,其它的可自行實(shí)現(xiàn)或者關(guān)注我后續(xù)開(kāi)源的代碼。
rt_err_tpwm_inputcap_init(structpwm_inputcapture_device*pwm_incap)
{
uint32_tsys_clk_freq;
uint32_ttimer_prescaler=1;
uint32_ttrigger_ch;
timer_parameter_structTimerConfig;
timer_(ic)_parameter_structTimerICConfig;
structgd32_pwm_inputcapture_devicepwm_incap_device;
pwm_incap_device=(structgd32_pwm_inputcapture_device)pwm_incap;
rcu_periph_clock_enable(pwm_incap_device->timer_rcu);
rcu_periph_clock_enable(pwm_incap_device->GPIO_rcu);
gpio_init(pwm_incap_device->GPIOx,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,pwm_incap_device->PINx);
sys_clk_freq=rcu_clock_freq_get(CK_SYS);
LOG_I("systemclockfrequency:%d",sys_clk_freq);
TimerConfig.alignedmode=TIMER_COUNTER_EDGE;
TimerConfig.clockdivision=TIMER_CKDIV_DIV1;
TimerConfig.counterdirection=TIMER_COUNTER_UP;
TimerConfig.period=65535U;
do{
if(sys_clk_freq/timer_prescaler/TimerConfig.periodinput_freq_min)
break;
if(timer_prescaler==65536)
{
rt_kprintf("(can)notconfiguretheprescalerf(or)inputsignalfrequency:%dhzn",pwm_incap_device->input_freq_min);
returnRT_ERROR;
}
timer_prescaler++;
}while(1);
TimerConfig.prescaler=timer_prescaler-1;
TimerConfig.repetitioncounter=0;
timer_init(pwm_incap_device->timerx,
LOG_I("%stimerprescaler:%d",pwm_incap_device->name,timer_prescaler);
TimerICConfig.icfilter=10;
TimerICConfig.icpolarity=TIMER_IC_POLARITY_RISING;
TimerICConfig.icprescaler=TIMER_IC_PSC_DIV1;
TimerICConfig.icselection=TIMER_IC_SELECTION_DIRECTTI;
timer_input_pwm_capture_config(pwm_incap_device->timerx,pwm_incap_device->input_ch,
timer_interrupt_flag_clear(pwm_incap_device->timerx,TIMER_INT_FLAG_UP);
timer_interrupt_enable(pwm_incap_device->timerx,TIMER_INT_UP);
trigger_ch=((pwm_incap_device->input_ch==TIMER_CH_0)?TIMER_SMCFG_TRGSEL_CI0FE0:TIMER_SMCFG_TRGSEL_CI1FE1);
timer_input_trigger_source_select(pwm_incap_device->timerx,trigger_ch);
timer_slave_mode_select(pwm_incap_device->timerx,TIMER_SLAVE_MODE_RESTART);
timer_external_trigger_config(pwm_incap_device->timerx,TIMER_EXT_TRI_PSC_OFF,TIMER_ETP_RISING,10);
NVIC_SetPriority(pwm_incap_device->timerx_irqn,3);
NVIC_EnableIRQ(pwm_incap_device->timerx_irqn);
timer_enable(pwm_incap_device->timerx);
returnRT_EOK;
}
voidpwm_inputcapture_update_isr(structgd32_pwm_inputcapture_devicedevice)
{
uint32_twidth_ch;
/TIMUpdateevent*/
if(timer_interrupt_flag_get(device->timerx,TIMER_INT_FLAG_UP)!=RESET)
{
timer_interrupt_flag_clear(device->timerx,TIMER_INT_FLAG_UP);
device->pwm_inputcap.pulse_param.pulsecycle_us=timer_channel_capture_value_register_re(ad)(device->timerx,device->input_ch);
width_ch=((device->input_ch==TIMER_CH_0)?(TIMER_CH_1):(TIMER_CH_0));
device->pwm_inputcap.pulse_param.pulsewidth_us=timer_channel_capture_value_register_read(device->timerx,width_ch);
rt_hw_pwm_inputcapture_isr(device);
}
}
修改工程構(gòu)建文件
修改相關(guān)SConscript文件
在“l(fā)ibraries/gd32_drivers/SConscript”文件內(nèi)的適當(dāng)位置加入如下代碼:
ifGetDepend(['RT_USING_PWM_INPUT_CAPTURE']):
src+=['drv_pwm_inputcapture.c']
在“rt-thread/components/drivers/misc/SConscript”文件內(nèi)的適當(dāng)位置加入如下代碼:
ifGetDepend(['RT_USING_INPUT_CAPTURE']):
src=src+['rt_inputcapture.c']
意思很簡(jiǎn)單,就是當(dāng)rtconfig.h內(nèi)定義了”RT_USING_PWM_INPUT_CAPTURE”宏,則把“drv_pwm_inputcapture.c”和“rt_inputcapture.c”驅(qū)動(dòng)文件加入工程,更準(zhǔn)確的是加入編譯。
修改相關(guān)Kconfig文件
在“rt-thread/components/drivers/Kconfig”文件內(nèi)的適當(dāng)位置加入如下代碼:
configRT_USING_INPUT_CAPTURE
bool"UsingINPUTCAPTUREdevicedrivers"
defaultn
管理BSP驅(qū)動(dòng)代碼的Kconfig文件不再librares目錄下,而是在board目錄下。于是在“board/Kconfig”文件內(nèi)的適當(dāng)位置,仿照其它驅(qū)動(dòng)加入如下代碼:
menuconfigBSP_USING_PWM_INPUTCAPTURE
bool"Enablepwminputcapture"
defaultn
selectRT_USING_PWM_INPUT_CAPTURE
ifBSP_USING_PWM_INPUTCAPTURE
configBSP_USING_PWM_INPUTCAPTURE1
bool"Enablepwminputcapture1"
defaultn
configBSP_USING_PWM_INPUTCAPTURE2
bool"Enablepwminputcapture2"
defaultn
configBSP_USING_PWM_INPUTCAPTURE3
bool"Enablepwminputcapture3"
defaultn
configBSP_USING_PWM_INPUTCAPTURE4
bool"Enablepwminputcapture4"
defaultn
configBSP_USING_PWM_INPUTCAPTURE5
bool"Enablepwminputcapture5"
defaultn
configBSP_USING_PWM_INPUTCAPTURE6
bool"Enablepwminputcapture6"
defaultn
endif
意思也比較簡(jiǎn)單,我這里適配了6個(gè)PWM的輸入捕獲驅(qū)動(dòng),并且利用“select”語(yǔ)句,在BSP的驅(qū)動(dòng)管理里面自動(dòng)開(kāi)啟了RTT驅(qū)動(dòng)里面的“RT_USING_PWM_INPUT_CAPTURE”選項(xiàng)。修改完上述代碼后,就可以用menuconfig命令或者RTThreadIDE的RT-ThreadSettings圖形配置界面內(nèi)進(jìn)行配置了:
測(cè)試
驅(qū)動(dòng)有了,再在頂層邏輯內(nèi)創(chuàng)建并實(shí)現(xiàn)兩個(gè)測(cè)試線程:
intmain(void)
{
...
rt_thread_tMotorL_encoder_thread;
MotorL_encoder_thread=rt_thread_create("MotorLEncoder",MotorLEncoder_thread_entry,RT_NULL,1024,4,20);
rt_thread_startup(MotorL_encoder_thread);
rt_thread_tMotorR_encoder_thread;
MotorR_encoder_thread=rt_thread_create("MotorREncoder",MotorREncoder_thread_entry,RT_NULL,1024,4,20);
rt_thread_startup(MotorR_encoder_thread);
...
}
voidMotorLEncoder_thread_entry(void*parameter)
{
rt_device_tLpwm_input_dev;
rt_uint16_tw(ai)t_i;
structpwm_inputcapture_device*inputcap_dev;
Lpwm_input_dev=rt_device_find("pwm_inputcap1");
if(Lpwm_input_dev==RT_NULL)
return;
inputcap_dev=(structpwm_inputcapture_device*)Lpwm_input_dev;
rt_device_open(Lpwm_input_dev,RT_DEVICE_OFLAG_RDONLY);
while(1)
{
if(inputcap_dev->sem!=RT_NULL)
{
rt_sem_take(inputcap_dev->sem,RT_WAITING_FOREVER);
if(wait_i++>=1000)
{
rt_kprintf("MotorLencoder:tt%dn",inputcap_dev->pulse_param.pulsewidth_us*10000/inputcap_dev->pulse_param.pulsecycle_us);
wait_i=0;
}
}
}
}
voidMotorREncoder_thread_entry(void*parameter)
{
rt_device_tRpwm_input_dev;
rt_uint16_twait_i;
structpwm_inputcapture_de
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 浸水擋土墻路堤邊坡穩(wěn)定性分析-課件(-精)
- 《逆全球化粗略綜述》課件
- 《輸卵管與子宮》課件
- 2024年甲乙雙方二手機(jī)床設(shè)備買(mǎi)賣(mài)合同
- 拉頭生產(chǎn)合同范本(2篇)
- 《OCTAVE評(píng)估方法》課件
- 2025年煙臺(tái)貨物從業(yè)資格證考試
- 2025年寶雞貨運(yùn)從業(yè)資格證試題庫(kù)及答案
- 2025年玉溪貨運(yùn)考試題目
- 2025年丹東c1貨運(yùn)從業(yè)資格證考試題
- 北京市海淀區(qū)2023-2024學(xué)年八年級(jí)上學(xué)期期末英語(yǔ)試卷
- 果品類(lèi)原料的烹調(diào)應(yīng)用課件
- 24節(jié)氣中的傳統(tǒng)服飾與飾品
- 地彈簧行業(yè)分析
- 如何發(fā)揮采購(gòu)在公司高質(zhì)量發(fā)展中作用
- 民事糾紛及其解決機(jī)制課件
- 美術(shù)高考總結(jié)匯報(bào)
- 北宋詞之臨江仙夜歸臨皋【宋】蘇軾課件
- 監(jiān)理質(zhì)量評(píng)估報(bào)告
- 《中國(guó)封建社會(huì)》課件
- 藥物代謝動(dòng)力學(xué)-中國(guó)藥科大學(xué)中國(guó)大學(xué)mooc課后章節(jié)答案期末考試題庫(kù)2023年
評(píng)論
0/150
提交評(píng)論