平台:mt6737m
舵機:模擬舵機
知識儲備:
舵機:介面:vcc,gnd,訊號
原理:乙個20ms左右的時基脈衝,該脈衝的高電平部分一般為0.5ms-2.5ms範圍內的角度控制脈衝。
簡單講,就是乙個50hz的pwm波形,脈寬(高電平)範圍在0.5~2.5ms變化,控制角度的變化。
我們平台用了10個舵機,mtk平台沒那麼多pwm輸出介面,怎麼辦?
1、硬體介面,需要10路pwm輸出(10個舵機角度控制一致,那全部掛一路沒問題,好像沒這種需求吧)
在android平台用的最多的裝置就是i2c了,也相對比較好調,所以找了一款ic,i2c轉pwm輸出,ic:pca9685。
值得慶幸的是,這款ic linux有支援。\kernel-3.18\drivers\pwm\pwm-pca9685.c
2、又是俗套的i2c裝置,驅動註冊過程了。此處不表。
3、看datasheet,初始化,工作過程等等。
好多人估計要找pca9685的初始化**,記錄一下吧。(針對模擬舵機的訊號需求)
pca9685_pwm_freq_init(50);//設定頻率
pca9685_i2c_mask_write( pca9685_mode1, mode1_sleep, 0x0);//喚醒
static void pca9685_pwm_freq_init(unsigned int freq)
//同時設定所有通道pwm脈寬
reg = pca9685_all_led_on_l;
pca9685_i2c_write( reg, 0);
reg = pca9685_all_led_on_h;
pca9685_i2c_write( reg, 0);
reg = pca9685_all_led_off_h;
pca9685_i2c_write(reg, 0x7);
reg = pca9685_all_led_off_l;
pca9685_i2c_write( reg, 0xd0);
//設定單個通道pwm脈寬
reg = led_n_off_l(num);
temp_l = pca9685_i2c_read(reg);
reg = led_n_off_h(num);
temp_h = pca9685_i2c_read(reg);
duty = (((long)temp_h << 8) & 0xf00) + (long)(temp_l &0xff);
//獲取單個通道pwm脈寬
reg = led_n_off_l(num);
pca9685_i2c_write( reg, duty & 0xff);
reg = led_n_off_h(num);
pca9685_i2c_write( reg, (duty >> 8) & 0xf);
這個函式我認為也需要記錄一下,雖然不是我寫的,但是我覺得思想不錯。
static int pca9685_i2c_mask_write(unsigned int reg,unsigned int mask, unsigned int val)
4、舵機控制演算法,不是很複雜,說說思想吧。
輸入:目標角度degree_m 速度speed
a、獲取當前角度 degree_cur
b、計算目標角度和當前角度的角度差(要轉多少度)|degree_m-degree_cur|=degree
1》定步長
speed/(degree/步長=要轉動多少次)=每一次轉動所需的時間
2》定時間片
degree/ (speed/時間片 = 要轉動多少次 ) = 每一次轉動的角度
除錯模擬I2C遇到的問題
最近一直在調模擬i2c,使用的是rtt提供的模擬i2c的驅動,工作是從stm32f302移植到stm32f103,主要的改動在於定時器和gpio。除錯幾天之後發現總是沒有ack,一直懷疑是在讀ack的時候沒有把sda的gpio配置為輸入模式,但也沒有去深究 太不嚴謹了!定時器確定沒有問題之後,問題肯...
i2c除錯記錄
i2c簡單時序關係 平時clk sda都為高電平 當clk為高,sda發生一次下降沿,觸發開始訊號 然後由clk的高電平期間取樣 sda資料,在clk高時候需要保持sda 先傳送7位位址和一位讀寫標誌 所以i2c位址一般是7位的 然後接收端回乙個ack 然後傳送8位reg位址,回乙個ack 然後就是...
軟體模擬I2C時輸入與輸出切換
一 為達到類似c51的操作需要新增以下位帶操作 include stm32f10x gpio.h include stm32f10x conf.h io位址對映 define gpioa odr addr gpioa base 12 0x4001080c define gpiob odr addr ...