基于STM32F4的多摩川協(xié)議通訊實現(xiàn)詳解
1、介紹
? ? ?編碼器,我們都知道在伺服控制中,為了獲取更高的位置精度,完成更精細(xì)的絕對定位,通常會采用絕對式光電編碼器作為位置反饋傳感器,其常見的兩種主要是17位與23位,編碼器廠商為了增強(qiáng)信息傳輸可靠性,編碼信息一般會采用串行方式輸出,通過特定的通訊協(xié)議控制。這里我們主要介紹一下17位絕對式光電編碼器。
2、編碼器
2.1、接口定義

說明:實際應(yīng)用過程中,如果沒有多圈值記錄需求,可以不接電池,但如果需要長時間保留多圈值數(shù)據(jù),比如多軸機(jī)器人的原點(diǎn)數(shù)據(jù),這種情況則需要接入電池。
2.2、電氣參數(shù)
說明:1、輸出信號符合RS485接口,負(fù)載電流Imax:±50mA;
? 2、消耗電流:≤120mA(無負(fù)載情況);
? 3、絕緣阻抗10MΩ以上(0V與殼之間,DC500V);
2.2、通訊電路

說明:1、IC1為線性差分驅(qū)動器,功能等同于MAX485;
???????????? 2、IC2為線性差分接收器,功能等同于MAX485,推薦使用ADM485;
? 3、匹配電阻:編碼器匹配電阻R2為220Ω,推薦用戶接收端匹配電阻R5≥120Ω;
? 4、上/下拉電阻:編碼器上/下拉電阻R1、R3為4.7KΩ,推薦用戶接收端上/下拉電阻R4、R6不小于1KΩ。
2.3、協(xié)議
根據(jù)編碼器電氣參數(shù)與通訊電路,我們可以確定通訊方式,STM32采用USART模塊,串口波特率設(shè)置2.5Mbps,以下是多摩川協(xié)議時序圖:
說明:1、CF:控制域,用戶發(fā)送命令CF與編碼器返回的CF一致;
? 2、SF:狀態(tài)域,編碼器返回錯誤信息與報警信息;
? 3、DF:數(shù)據(jù)域,編碼器返回數(shù)據(jù);
? 4、CRC:校驗域,CRC多項式:G(X)=??8+1,校驗范圍CF、SF、DF。
2.3.1、控制字CF

說明:1、根據(jù)時序圖可以知道發(fā)送請求只需要發(fā)送CF即可,具體CF值可以根據(jù)上表分析,CF結(jié)構(gòu)主要是start bit(0)+sink code+Data ID code+ID parity+Delimiter(1),這里注意一下開始位(0)與結(jié)束位(1),與串口無校驗發(fā)送里面的開始位與結(jié)束位一樣的嘛,所以我們其實只需要發(fā)送sink code+Data ID code+ID parity就可以了;
? 2、根據(jù)時序圖可以看到sink code 固定為010,剩下的Data ID code+ID parity看自己需求查表對應(yīng)上就行,經(jīng)常用的主要是ID0=0x02與ID3=0x1A,其余我就不說了,貼代碼。
? 3、這里注意一下,編碼器返回的報文CF位必須與發(fā)送CF一致,在處理接收報文時需校驗一下。
/* 宏定義聲明 —————————————————————-*/
#define ? ? ? ? DataId0 ? ? ? ? ? ? 0x02 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*讀取單圈*/
#define ? ? ? ? DataId1 ? ? ? ? ? ? 0x8A ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*讀取圈數(shù)*/
#define ? ? ? ? DataId2 ? ? ? ? ? ? 0x92 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*讀取編碼器編號*/
#define ? ? ? ? DataId3 ? ? ? ? ? ? 0x1A ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*讀取單圈+圈數(shù)*/
#define ? ? ? ? DataId6 ? ? ? ? ? ? 0x32 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*寫EEPROM*/
#define ? ? ? ? DataIdD ? ? ? ? ? ? 0xEA ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*讀EEPEOM*/
#define ? ? ? ? DataId7 ? ? ? ? ? ? 0xBA ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*重置錯誤ERROR*/
#define ? ? ? ? DataId8 ? ? ? ? ? ? 0xC2 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*重置圈數(shù)*/
#define ? ? ? ? DataIdC ? ? ? ? ? ? 0x62 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*重置圈數(shù)與ERROR*/ ?
2.3.2、狀態(tài)字SF

說明:狀態(tài)位SF主要反饋編碼器狀態(tài),包括編碼器是否過熱、電池供電是否正常、數(shù)據(jù)解析是否正確等。
2.3.3、數(shù)據(jù)字DF
根據(jù)發(fā)出的CF不同,編碼器返回的DF也會不同,具體的對應(yīng)關(guān)系如下表:

說明:1、ABS0-ABS2:編碼器單圈值,由于STM32的串口是小端模式,所以實際 編碼器單圈位置值=(ABS2<<16)|(ABS1<<8)|(ABS0<<0);
? 2、ABM0-ABM2:編碼器圈數(shù)值,實際編碼器圈數(shù)值=(ABM2<<16)|(ABM1<<8)|(ABM0<<0)。

說明:ALMC:編碼器錯誤,不同數(shù)值都有其對應(yīng)的故障,對應(yīng)查表即可。
2.4.4、校驗字CRC

說明:這里注意一下,我們采用的是小端異或的計算方式,根據(jù)多項式 G(X)=??8+1 其對應(yīng)的二進(jìn)制數(shù)為0x101,其Ploy值為0x01,LSB First=0x80,我們需要將CF+SF+DF以字節(jié)形式分別于LSB First進(jìn)行亦或處理,最后結(jié)果為CRC8校驗結(jié)果,具體實現(xiàn)過程見代碼。
/******************************************************************************
? * 函數(shù)功能: ? CRC8校驗函數(shù)
? * 輸入?yún)?shù): ? *message:接收的數(shù)據(jù)指針
? ? ? ? ? ? ? ? len:數(shù)據(jù)長度
? * 返 回 值: ? ? ?CRC8校驗值
? ? * 說 ? ?明: 多項式:G(X)=X^8+1 LSB first ?Poly: 0000 0001
? ? ? ? ? ? ? ? ? ? ? ? LSB first ?: 1000 0000 =0X80
*****************************************************************************/ ?
uint8_t APP_Math_CRC8_ChkValue(uint8_t *message, uint8_t len)
{
? ? uint8_t crc_val;
? ? uint8_t i;
? ? crc_val = 0;
? ? while(len–)
? ? {
? ? ? ? crc_val ^= *message++;
? ? ? ? for(i = 0;i < 8;i++)
? ? ? ? {
? ? ? ? ? ? if(crc_val & 0x01)
? ? ? ? ? ? ? ? crc_val = (crc_val >> 1) ^ 0X80;
? ? ? ? ? ? else
? ? ? ? ? ? ? ? crc_val >>= 1;
? ? ? ? }
? ? }
? ? return crc_val;
}
3、單片機(jī)
3.1、單片機(jī)
當(dāng)時項目為了上手快一點(diǎn),又怕串口波特率不夠,所以就選了個STM32F405RGT6,168MHz主頻綽綽有余,現(xiàn)在想想有點(diǎn)殺雞用牛刀了,這里主要提一下接下來要用到的串口與DMA。STM32F405有16數(shù)據(jù)流DMA,支持FIFOs模式與觸發(fā)模式,4 個 USART/2 個 UART(速率可達(dá)10.5 Mbit/s,支持ISO7816接口)。

3.2、串口+DMA
?串口(UART)是一種低速的串行異步通信,通常使用的波特率小于或等于115200bps,對于這種數(shù)據(jù)量不大的通信場景,一般沒必要使用DMA,或者說使用DMA并未能充分發(fā)揮出DMA的作用。當(dāng)面對數(shù)量大或者高波特率時,就必須使用DMA以釋放CPU資源,因為高波特率可能帶來CPU資源過度浪費(fèi)的問題。這里編碼器電氣參數(shù)要求通訊速率≥2.5MHz,我們一般選擇將串口波特率設(shè)置為2.5MHz,同時為了不占用太多CPU資源,CF發(fā)送與編碼器數(shù)據(jù)接收都會采用DMA,具體寄存器設(shè)置如下:
/******************************************************************************
? * 函數(shù)功能: ? USART2+DMA初始化函數(shù)
? * 輸入?yún)?shù): ? 無
? * 返 回 值: ? ? ?無
? ? * 說 ? ?明: ? 外部調(diào)用-多摩川編碼器1
*****************************************************************************/ ?
void BSP_Encoder1_InitConfig(void)
{
? ? GPIO_InitTypeDef ? ?GPIO_InitStructure;
? ? USART_InitTypeDef USART_InitStructure;
? ? DMA_InitTypeDef ? ? DMA_InitStructure;
? ? NVIC_InitTypeDef ? ?NVIC_InitStructure;
? ?
? ? RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
? ? RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
? ? GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*UART2-TX*/
? ? GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*UART2-RX*/
? ? GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
? ? GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
? ? GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
? ? GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*UART2-TX*/
? ? GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
? ? GPIO_Init(GPIOA, &GPIO_InitStructure);
? ? GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
? ? GPIO_Init(GPIOA, &GPIO_InitStructure); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*UART2-RX*/
? ?
? ? RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); ?
? ? GPIO_InitStructure.GPIO_Pin ? = GPIO_Pin_15; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*DIR1-PC15*/
? ? GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; ?
? ? GPIO_InitStructure.GPIO_Mode ?= GPIO_Mode_OUT;
? ? GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
? ? GPIO_InitStructure.GPIO_PuPd ?= GPIO_PuPd_UP; ?
? ? GPIO_Init(GPIOC, ? ?&GPIO_InitStructure); ?
? ? GPIO_ResetBits(GPIOC,GPIO_Pin_15); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*初始化關(guān)閉通信*/
? ?
? ? RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*串口發(fā)DMA配置*/
? ? NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*搶占優(yōu)先級0-3,響應(yīng)優(yōu)先級0-3*/
? ? NVIC_InitStructure.NVIC_IRQChannel=DMA1_Stream6_IRQn; ? ? ? ? ? ? ?
? ? NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*搶占優(yōu)先級1*/
? ? NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
? ? NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
? ? NVIC_Init(&NVIC_InitStructure); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*DMA發(fā)送中斷*/
? ? DMA_DeInit(DMA1_Stream6); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*DMA通道配置*/
? ? while(DMA_GetCmdStatus(DMA1_Stream6)!=DISABLE){} ? ?
? ? DMA_InitStructure.DMA_Channel = DMA_Channel_4;
? ? DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART2->DR); ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*外設(shè)地址*/
? ? DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Ed_Tx_Buf1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*內(nèi)存地址*/
? ? DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*dma傳輸方向*/
? ? DMA_InitStructure.DMA_BufferSize = USART_MAX_TX_LEN; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*設(shè)置DMA在傳輸時緩沖區(qū)的長度*/
? ? DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*設(shè)置DMA的外設(shè)遞增模式,一個外設(shè)*/
? ? DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*設(shè)置DMA的內(nèi)存遞增模式*/
? ? DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; ? ? ? ? ? ? ? ? ? ? ? ? /*外設(shè)數(shù)據(jù)字長*/
? ? DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*內(nèi)存數(shù)據(jù)字長*/
? ? DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*設(shè)置DMA的傳輸模式*/
? ? DMA_InitStructure.DMA_Priority = DMA_Priority_High; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*設(shè)置DMA的優(yōu)先級別*/
? ? DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*指定如果FIFO模式或直接模式將用于指定的流:不使能FIFO模式*/ ?
? ? DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*指定了FIFO閾值水平*/ ?
? ? DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*指定的Burst轉(zhuǎn)移配置內(nèi)存?zhèn)鬏?/
? ? DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*指定的Burst轉(zhuǎn)移配置外圍轉(zhuǎn)移*/
? ? DMA_Init(DMA1_Stream6, &DMA_InitStructure); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*配置DMA1的通道*/ ? ?
? ? DMA_ITConfig(DMA1_Stream6,DMA_IT_TC,ENABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*使能中斷*/
? ?
? ? DMA_DeInit(DMA1_Stream5); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*串口接收DMA配置*/
? ? while(DMA_GetCmdStatus(DMA1_Stream5)!=DISABLE){} ? ? ? ?
? ? DMA_InitStructure.DMA_Channel = DMA_Channel_4;
? ? DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART2->DR); ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*外設(shè)地址*/
? ? DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Ed_Rx_Buf1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*內(nèi)存地址*/
? ? DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*DMA傳輸方向*/
? ? DMA_InitStructure.DMA_BufferSize = USART_MAX_RX_LEN; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*設(shè)置DMA在傳輸時緩沖區(qū)的長度*/
? ? DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*設(shè)置DMA的外設(shè)遞增模式,一個外設(shè)*/
? ? DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*設(shè)置DMA的內(nèi)存遞增模式*/
? ? DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; ? ? ? ? ? ? ? ? ? ? ? ? /*外設(shè)數(shù)據(jù)字長*/
? ? DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*內(nèi)存數(shù)據(jù)字長*/
? ? DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*設(shè)置DMA的傳輸模式*/
? ? DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*設(shè)置DMA的優(yōu)先級別*/
? ? DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*指定如果FIFO模式或直接模式將用于指定的流 : 不使能FIFO模式*/ ? ?
? ? DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*指定了FIFO閾值水平*/ ? ?
? ? DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*指定的Burst轉(zhuǎn)移配置內(nèi)存?zhèn)鬏?/ ? ? ?
? ? DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*指定的Burst轉(zhuǎn)移配置外圍轉(zhuǎn)移*/
? ? DMA_Init(DMA1_Stream5, &DMA_InitStructure); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*配置DMA1的通道*/ ?
? ? DMA_Cmd(DMA1_Stream5,ENABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*使能通道*/
? ? USART_InitStructure.USART_BaudRate = ENCODER1_BAUDRATE; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*配置8 1 0*/
? ? USART_InitStructure.USART_WordLength = USART_WordLength_8b;
? ? USART_InitStructure.USART_StopBits = USART_StopBits_1;
? ? USART_InitStructure.USART_Parity = USART_Parity_No ;
? ? USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
? ? USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
? ? USART_Init(USART2, &USART_InitStructure);
? ?
? ? NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*通道設(shè)置為串口中斷*/ ?
? ? NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*中斷占先等級*/
? ? NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*中斷響應(yīng)優(yōu)先級*/
? ? NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*打開中斷*/ ?
? ? NVIC_Init(&NVIC_InitStructure); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*配置中斷*/ ?
? ?
? ? USART_DMACmd(USART2,USART_DMAReq_Tx,ENABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*采用DMA方式發(fā)送*/
? ? USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*采用DMA方式接收*/
? ? USART_ITConfig(USART2,USART_IT_TC,DISABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*中斷配置*/
? ? USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);
? ? USART_ITConfig(USART2,USART_IT_TXE,DISABLE);
? ? USART_ITConfig(USART2,USART_IT_IDLE,ENABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*開啟USART2空中斷*/
? ? USART_Cmd(USART2, ENABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*啟動串口*/ ?
}
另附DMA1、DMA2每個控制的8個數(shù)據(jù)流和其對應(yīng)的通道:
?


4、代碼實現(xiàn)
至此串口DMA初始化完成,接下來就是具體的發(fā)送與接收,發(fā)送直接采用DMA傳輸完成中斷,接收稍微需要點(diǎn)處理,因為我們接收的是不定長度的數(shù)據(jù),所以需要通過串口的空閑中斷來判斷數(shù)據(jù)接收結(jié)束,數(shù)據(jù)接收完畢之后需要對CF、CRC進(jìn)行校驗,校驗通過才可認(rèn)為DF數(shù)據(jù)可用,具體代碼實現(xiàn)如下:
/******************************************************************************
? * 函數(shù)功能: ? ? ? USART2中斷處理函數(shù)
? * 輸入?yún)?shù): ? 無
? * 返 回 值: ? ? ?無
? ? * 說 ? ?明: ? 外部調(diào)用-多摩川編碼器1
*****************************************************************************/ ?
void USART2_IRQHandler(void) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*串口2中斷服務(wù)程序*/
{
? ? if(USART_GetITStatus(USART2,USART_IT_IDLE)!=RESET) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*空閑中斷觸發(fā)*/
? ? {
? ? ? ? DMA_Cmd(DMA1_Stream5, DISABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 暫時關(guān)閉DMA數(shù)據(jù)尚未處理 */
? ? ? ? ED_RX_LEN1 = USART_MAX_RX_LEN – DMA_GetCurrDataCounter(DMA1_Stream5); ? ? ? ? ? ? ? ? ? ? ? /* 獲取接收到的數(shù)據(jù)長度*/
? ? ? ? BSP_Encoder1_DMA_DataProcess(Ed_Tx_Buf1,Ed_Rx_Buf1,ED_RX_LEN1); ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 報文數(shù)據(jù)處理*/
? ? ? ? DMA_ClearFlag(DMA1_Stream5,DMA_FLAG_TCIF5); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* 清DMA標(biāo)志位 */
? ? ? ? DMA_SetCurrDataCounter(DMA1_Stream5,USART_MAX_RX_LEN); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* 重新賦值計數(shù)值,必須大于等于最大可能接收到的數(shù)據(jù)幀數(shù)目 */
? ? ? ? DMA_Cmd(DMA1_Stream5, ENABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*打開DMA*/
? ? ? ? USART_ReceiveData(USART2); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*清除空閑中斷標(biāo)志位,接收函數(shù)有清標(biāo)志位的作用*/
? ? ? ? Ed_Flag_Rx_Busy1 = 1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*狀態(tài)位更新-USART2接收完成*/ ? ? ? ? ? ?
? ? }
? ? if(USART_GetFlagStatus(USART2,USART_IT_TXE)==RESET) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*串口發(fā)送完成*/
? ? {
? ? ? ? Ed_Flag_Tx_Busy1=0; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? USART_ITConfig(USART2,USART_IT_TC,DISABLE);
? ? }
}
/******************************************************************************
? ? * 函數(shù)功能: ? ? DMA1_Stream6中斷處理函數(shù)
? ? * 輸入?yún)?shù): ? ? 無
? ? * 返 回 值: ? ?無
? ? * 說 ? ?明: ? 外部調(diào)用-多摩川編碼器1
*****************************************************************************/ ?
void DMA1_Stream6_IRQHandler(void)
{
? ? if(DMA_GetFlagStatus(DMA1_Stream6,DMA_FLAG_TCIF6)!=RESET) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*等待DMA1_Steam6傳輸完成*/
? ? {
? ? ? ? DMA_ClearFlag(DMA1_Stream6,DMA_FLAG_TCIF6); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*清除DMA1_Steam6傳輸完成標(biāo)志*/
? ? ? ? DMA_Cmd(DMA1_Stream6,DISABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*關(guān)閉使能*/
? ? ? ? USART_ITConfig(USART2,USART_IT_TC,ENABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*打開串口發(fā)送完成中斷*/
? ? }
}
/******************************************************************************
? ? * 函數(shù)功能: ? ? DMA_USART2發(fā)送函數(shù)
? ? * 輸入?yún)?shù): ? ? *data:發(fā)送的數(shù)據(jù)指針
? ? ? ? ? ? ? ? ? ? size:數(shù)據(jù)長度
? ? * 返 回 值: ? ?無
? ? * 說 ? ?明: ? 外部調(diào)用-多摩川編碼器1
*****************************************************************************/ ?
void BSP_Encoder1_DMA_SendBuffer(u8 *data,u16 size) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
{
? ? Ed_Flag_Tx_Busy1=1; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*狀態(tài)位更新-USART2發(fā)送中*/
? ? memcpy(Ed_Tx_Buf1,data,size); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*復(fù)制數(shù)據(jù)到DMA發(fā)送緩存區(qū)*/
? ? while (DMA_GetCmdStatus(DMA1_Stream6) != DISABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*確保DMA可以被設(shè)置*/
? ? DMA_SetCurrDataCounter(DMA1_Stream6,size); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/*設(shè)置數(shù)據(jù)傳輸長度*/
? ? DMA_Cmd(DMA1_Stream6,ENABLE); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*打開DMA數(shù)據(jù)流,開始發(fā)送*/
}
/******************************************************************************
? ? * 函數(shù)功能: ? ? DMA_USART2數(shù)據(jù)處理函數(shù)
? ? * 輸入?yún)?shù): ? ? *data:接收的數(shù)據(jù)指針
? ? ? ? ? ? ? ? ? ? size:數(shù)據(jù)長度
? ? * 返 回 值: ? ?無
? ? * 說 ? ?明: ? 外部調(diào)用-多摩川編碼器2
*****************************************************************************/ ?
void ? ?BSP_Encoder1_DMA_DataProcess(u8 *txdata,u8 *rxdata,u16 size)
{
? ? uint8_t ? ? crc=0;
? ? uint8_t ? ? buf[USART_MAX_RX_LEN]={0}; ?
? ? for(int i=0;i<size;i++)
? ? ? ? buf[i]=*rxdata++;
? ? if(buf[0]==*txdata)
? ? {
? ? ? ? crc=APP_Math_CRC8_ChkValue(buf,size-1);
? ? ? ? if(crc==buf[size-1])
? ? ? ? {
? ? ? ? ? ? Encoder1_CodeValue=buf[4]<<16|buf[3]<<8|buf[2];
? ? ? ? }
? ? ? ? else
? ? ? ? {
? ? ? ? ? ? Encoder_ReadFaultNum++;
? ? ? ? ? ? if(Encoder_ReadFaultNum>ED_READ_FAULT_MAXNUM)
? ? ? ? ? ? ? ? Encoder_ReadStatus=1; ? ? ? ? ?
? ? ? ? }
? ? }
? ? else
? ? {
? ? ? ? ? ? Encoder_ReadFaultNum++;
? ? ? ? ? ? if(Encoder_ReadFaultNum>ED_READ_FAULT_MAXNUM)
? ? ? ? ? ? ? ? Encoder_ReadStatus=1;
? ? }
}