在線做banner的網(wǎng)站網(wǎng)站發(fā)布與推廣方式
文章目錄
- 一、IBUS協(xié)議
- 二、SBUS協(xié)議
- 三、PPM信號(hào)
一、IBUS協(xié)議
IBUS(Intelligent Bus)是一種用于電子設(shè)備之間通信的協(xié)議,采用串行通信方式,允許多設(shè)備通過單一數(shù)據(jù)線通信,較低延遲,支持多主機(jī)和從機(jī)結(jié)構(gòu),常用于遙控器與天空端之間,富斯官網(wǎng)已公開協(xié)議,協(xié)議格式如下可見:
一共32字節(jié),2 字節(jié)幀頭+28字節(jié)數(shù)據(jù)位 + 2字節(jié)校驗(yàn)位組成
解碼如下:
#define IBUS_USER_CHANNELS 10
#define IBUS_LENGTH 0x20
#define IBUS_COMMAND40 0x40
#define IBUS_MAX_CHANNLES 14uint8_t rx_buffer[32] = {0};
uint16_t channel[IBUS_USER_CHANNELS] = {0};
uint16_t checksum_cal, checksum_ibus;void IBUS_READ_CHANNEL(uint8_t user_channels)
{uint16_t channel_buffer[IBUS_MAX_CHANNLES] = {0};if(rx_buffer[0] == IBUS_LENGTH && rx_buffer[1] == IBUS_COMMAND40){checksum_cal = 0xffff - rx_buffer[0] - rx_buffer[1];for(int i = 0; i < IBUS_MAX_CHANNLES; i++){channel_buffer[i] = (uint16_t)(rx_buffer[i * 2 + 3] << 8 | rx_buffer[i * 2 + 2]);checksum_cal = checksum_cal - rx_buffer[i * 2 + 3] - rx_buffer[i * 2 + 2];}checksum_ibus = rx_buffer[31] << 8 | rx_buffer[30];if(checksum_cal == checksum_ibus){for(int j = 0; j < user_channels; j++){channel[j] = channel_buffer[j];}}}HAL_UART_Receive_IT(IBUS_UART, rx_buffer, 32);
}
二、SBUS協(xié)議
SBUS(Serial Bus)也是一種用于遙控模型、無人機(jī)和其他應(yīng)用程序中的串行通信協(xié)議,特別是在飛控系統(tǒng)和遙控設(shè)備之間,以實(shí)現(xiàn)高效的數(shù)據(jù)傳輸。
采用串行通信,單線信號(hào)傳輸,支持最多16個(gè)通道的控制,實(shí)時(shí)性強(qiáng),可反向兼容PWM,設(shè)計(jì)考慮冗余性。
協(xié)議格式共有25字節(jié)數(shù)據(jù),由首部(1字節(jié))+ 數(shù)據(jù)(22字節(jié))+ 標(biāo)志位(1字節(jié))+ 結(jié)束符(1字節(jié))
組成
- 幀頭: 0x0F
- 數(shù)據(jù): 22 字節(jié)的數(shù)據(jù),分別代表16個(gè)通道的數(shù)據(jù),也即是每個(gè)通道的值用了 11 位來表示,22x8/16 = 11,每個(gè)通道的取值范圍為 0~2047,低位在前、高位在后
- 標(biāo)志位: 1字節(jié),高四位從高到低依次表示:
bit7:CH17數(shù)字通道
bit6:CH16數(shù)字通道
bit5:幀丟失(Frame lost)
bit4:安全保護(hù)(Failsafe):失控保護(hù)激活位(0x10)判斷飛機(jī)是否失控
bit3~bit0:低四位不用 - 結(jié)束符: 0x00
通道解析:
解碼如下:
#define USART_BUF_SIZE 8
#define SBUS_DATA_SIZE 25
struct SBUS_t{uint8_t head; // 1字節(jié)幀頭uint16_t ch[16]; // 16個(gè)通道數(shù)據(jù)uint8_t flag; // 1字節(jié)標(biāo)志位uint8_t end; // 1字節(jié)結(jié)束
};uint8_t usart_buf[USART_BUF_SIZE];
uint8_t sbus_rx_head = 0; // 發(fā)現(xiàn)起始字節(jié) 0x0F
uint8_t sbus_rx_sta = 0; // sbus 接收狀態(tài),0:未完成,1:已完成一幀接收
uint8_t sbus_rx_index; // 接收字節(jié)計(jì)數(shù)
uint8_t sbus_rx_buf[SBUS_DATA_SIZE]; // 接收sbus數(shù)據(jù)緩沖區(qū)struct SBUS_t sbus; // SBUS 結(jié)構(gòu)體實(shí)例化void USART2_IRQHandler(void) //中斷函數(shù)
{uint8_t chr;if ((__HAL_UART_GET_FLAG(&UART2_Handler, UART_FLAG_RXNE) != RESET)) // 接收中斷{HAL_UART_Receive(&UART2_Handler, &chr, 1, 1000); // 接收一個(gè)字符if (sbus_rx_sta == 0) // 接收未完成{if ((chr == 0x0F) || sbus_rx_head) // 找到首字節(jié)或已經(jīng)找到首字節(jié){sbus_rx_head = 1; // 標(biāo)明已經(jīng)找到首字母if (sbus_rx_index < SBUS_DATA_SIZE) // 未接收到25個(gè)字符{sbus_rx_buf[sbus_rx_index] = chr; // 不斷接收sbus_rx_index ++;}else // 接收到25個(gè)字符了{sbus_rx_sta = 1; // 接收完成sbus_rx_head = 0; // 清零,準(zhǔn)備下一次接收sbus_rx_index = 0;}}}}HAL_UART_IRQHandler(&UART2_Handler);
}/* 對(duì)SBUS協(xié)議數(shù)據(jù)進(jìn)行解析 */
/* 實(shí)現(xiàn)對(duì)S.BUS協(xié)議緩存,頭部為 0x0F,結(jié)尾為 0x00, 中間22Bytes16通道數(shù)據(jù),1Byte標(biāo)志符 */
void SbusParseTask(void *arg)
{while (1){if(sbus_rx_sta==1) // 接收完一幀{NVIC_DisableIRQ(USART2_IRQn); // 要關(guān)閉中斷,防止讀寫混亂sbus.head = sbus_rx_buf[0]; // 首部sbus.flag = sbus_rx_buf[23]; // 標(biāo)志符sbus.end = sbus_rx_buf[24]; // 結(jié)尾sbus.ch[0] =((sbus_rx_buf[2]<<8) + (sbus_rx_buf[1])) & 0x07ff; sbus.ch[1] =((sbus_rx_buf[3]<<5) + (sbus_rx_buf[2]>>3)) & 0x07ff;sbus.ch[2] =((sbus_rx_buf[5]<<10) + (sbus_rx_buf[4]<<2) + (sbus_rx_buf[3]>>6)) & 0x07ff;sbus.ch[3] =((sbus_rx_buf[6]<<7) + (sbus_rx_buf[5]>>1)) & 0x07ff;sbus.ch[4] =((sbus_rx_buf[7]<<4) + (sbus_rx_buf[6]>>4)) & 0x07ff;sbus.ch[5] =((sbus_rx_buf[9]<<9) + (sbus_rx_buf[8]<<1) + (sbus_rx_buf[7]>>7)) & 0x07ff; sbus.ch[6] =((sbus_rx_buf[10]<<6) + (sbus_rx_buf[9]>>2)) & 0x07ff;sbus.ch[7] =((sbus_rx_buf[11]<<3) + (sbus_rx_buf[10]>>5)) & 0x07ff;sbus.ch[8] =((sbus_rx_buf[13]<<8) + sbus_rx_buf[12]) & 0x07ff;sbus.ch[9] =((sbus_rx_buf[14]<<5) + (sbus_rx_buf[13]>>3)) & 0x07ff;sbus.ch[10]=((sbus_rx_buf[16]<<10) + (sbus_rx_buf[15]<<2) + (sbus_rx_buf[14]>>6)) & 0x07ff;sbus.ch[11]=((sbus_rx_buf[17]<<7) + (sbus_rx_buf[16]>>1)) & 0x07ff;sbus.ch[12]=((sbus_rx_buf[18]<<4) + (sbus_rx_buf[17]>>4)) & 0x07ff;sbus.ch[13]=((sbus_rx_buf[20]<<9) + (sbus_rx_buf[19]<<1) + (sbus_rx_buf[18]>>7)) & 0x07ff;sbus.ch[14]=((sbus_rx_buf[21]<<6) + (sbus_rx_buf[20]>>2)) & 0x07ff;sbus.ch[15]=((sbus_rx_buf[22]<<3) + (sbus_rx_buf[21]>>5)) & 0x07ff;delay_ms(500); // 先做完延時(shí)再開啟中斷與下一次捕獲,否則延時(shí)期間中斷到來,沒有達(dá)到預(yù)期效果NVIC_EnableIRQ(USART2_IRQn); // 打開串口中斷sbus_rx_sta = 0; // 準(zhǔn)備下一次接收 }else{delay_ms(500); // 免得異常時(shí),到此處使得低優(yōu)先級(jí)任務(wù)無法執(zhí)行}}
}
三、PPM信號(hào)
PPM(Pulse Position Modulation,脈沖位置調(diào)制)信號(hào)是一種用于傳輸控制信號(hào)的調(diào)制方式,尤其在遙控系統(tǒng)中非常常見。PPM信號(hào)通過改變脈沖在時(shí)間上的位置來代表不同的信息,在遙控模型、無人機(jī)和一些工業(yè)控制系統(tǒng)中被廣泛應(yīng)用。
采用串行通信,信號(hào)頻率只有50Hz,略遜于ibus和sbus,對(duì)于一些高精度儀器不可用。
這里提一下,PWM表示脈沖寬度調(diào)制,也就是高電平維持的時(shí)間,而PPM實(shí)質(zhì)上就是將多個(gè)通道的PWM放到“一根線”上進(jìn)行傳輸,一個(gè)完整的PPM信號(hào)幀包含了多個(gè)通道的PWM值。
PPM信號(hào)一幀數(shù)據(jù)分為低電平(0.5ms)+高電平(0.5ms-1.5ms)
,高電平長度與PWM占空比成正比。因?yàn)橐粠盘?hào)最多要2ms,信號(hào)周期為20ms,所以理論一次PPM信號(hào)可以發(fā)送10幀數(shù)據(jù),但是由于要確定幀頭信號(hào),所以要加入同步幀,真正的PPM信號(hào)里面最多有9幀數(shù)據(jù)幀。
解析方式:①外部中斷 ②定時(shí)器輸入捕獲
考慮安全條件下,建議使用定時(shí)器輸入捕獲方式進(jìn)行解碼,具體解碼參考如下:
uint16_t PPM_Sample_Cnt=0;
uint32_t PPM_Time=0;
uint16_t PPM_Okay=0;
uint16_t PPM_Databuf[8]={0}; //PPM信號(hào)存儲(chǔ)
uint8_t TIM2_CH2_CAPTURE_STA=0;void TIM2_IRQHandler(void)
{if(TIM_GetITStatus(TIM2,TIM_IT_CC2)==!RESET)//捕獲中斷{if(TIM2_CH2_CAPTURE_STA&0x01)//符合條件的話說明上次捕獲了高電平,那么這次捕獲的一定是低電平{PPM_Time=TIM_GetCapture2(TIM2);if(PPM_Time>0)PPM_Time++; if(PPM_Okay==1){PPM_Databuf[PPM_Sample_Cnt]=PPM_Time;PPM_Sample_Cnt++;if(PPM_Sample_Cnt>8)PPM_Okay=0;}if(PPM_Time>7000)//識(shí)別到幀尾{PPM_Okay=1;PPM_Sample_Cnt=0;} TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);TIM2_CH2_CAPTURE_STA=0;//清掉標(biāo)志位準(zhǔn)備開始下一次上升沿和下降沿檢測(cè)}else{TIM_SetCounter(TIM2,0);//以上為清零 TIM2_CH2_CAPTURE_STA|=0x01;//高電平指示被賦值TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //當(dāng)捕獲上升沿后改為捕獲下降沿} }TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中斷標(biāo)志位,一定不要忘,要不然下次進(jìn)不了中斷
}