#申请原创# #技术资源#
使用APM32F425/APM32F427开发伺服方案,使用总线编码器时,可能包括SPI协议或UART协议的编码器,目前市面上应用较广泛的为多摩川协议,采用RS485通讯。代码采用极海自己开发的底层驱动库函数进行编写,想要学习使用原厂SDK搭建工程的同学可以看看如何调用底层函数。 RS485通讯配置是通过一路UART外设来实现的。整个配置过程包括: 1. 外设以及串口时钟使能 2. GPIO配置 3. DMA配置 4. 寄存器参数配置 使用极海SDK库函数编写的USART配置函数如下,函数采用了DMA来进行数据收发,DMA采用的是循环发送的方式,可以实现协议的高速连续收发: void MX_USART3_UART_Init(void) { USART_Config_T usartConfig = {0}; GPIO_Config_T gpioConfig = {0}; DMA_Config_T dmaConfig = {0}; /* Peripheral clock enable */ RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_USART3); RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOD); RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA1); /**USART3 GPIO Configuration PD12 ------> USART3_RTS PD8 ------> USART3_TX PD9 ------> USART3_RX */ gpioConfig.pin = RS485_TX_Pin|RS485_RX_Pin; gpioConfig.mode = GPIO_MODE_AF; gpioConfig.speed = GPIO_SPEED_100MHz; gpioConfig.otype = GPIO_OTYPE_PP; gpioConfig.pupd = GPIO_PUPD_NOPULL; GPIO_Config(GPIOD, &gpioConfig); GPIO_ConfigPinAF(GPIOD,GPIO_PIN_SOURCE_8 ,GPIO_AF_USART3); GPIO_ConfigPinAF(GPIOD,GPIO_PIN_SOURCE_9 ,GPIO_AF_USART3); dmaConfig.bufferSize = 0; dmaConfig.channel = DMA_CHANNEL_4; dmaConfig.dir = DMA_DIR_PERIPHERALTOMEMORY; dmaConfig.priority = DMA_PRIORITY_VERYHIGH; dmaConfig.loopMode = DMA_MODE_NORMAL; dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE; dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE; dmaConfig.memoryDataSize = DMA_MEMORY_DATA_SIZE_BYTE; dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_BYTE; dmaConfig.fifoMode = DMA_FIFOMODE_ENABLE; dmaConfig.fifoThreshold = DMA_FIFOTHRESHOLD_QUARTER; dmaConfig.memoryBurst = DMA_MEMORYBURST_SINGLE; dmaConfig.peripheralBurst = DMA_PERIPHERALBURST_SINGLE; dmaConfig.peripheralBaseAddr = (uint32_t)&USART3->DATA; dmaConfig.memoryBaseAddr = (uint32_t)Encoder_rxData; DMA_Config(DMA1_Stream1 ,&dmaConfig); /* DMA_TX Init */ dmaConfig.bufferSize = 0; dmaConfig.channel = DMA_CHANNEL_4; dmaConfig.dir = DMA_DIR_MEMORYTOPERIPHERAL; dmaConfig.priority = DMA_PRIORITY_VERYHIGH; dmaConfig.loopMode = DMA_MODE_NORMAL; dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE; dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE; dmaConfig.memoryDataSize = DMA_MEMORY_DATA_SIZE_BYTE; dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_BYTE; dmaConfig.fifoMode = DMA_FIFOMODE_ENABLE; dmaConfig.fifoThreshold = DMA_FIFOTHRESHOLD_QUARTER; dmaConfig.memoryBurst = DMA_MEMORYBURST_SINGLE; dmaConfig.peripheralBurst = DMA_PERIPHERALBURST_SINGLE; dmaConfig.peripheralBaseAddr = (uint32_t)&USART3->DATA; dmaConfig.memoryBaseAddr = (uint32_t)Encoder_txData; DMA_Config(DMA1_Stream3 ,&dmaConfig); USART_EnableDMA(USART3,USART_DMA_RX); USART_EnableDMA(USART3,USART_DMA_TX); usartConfig.baudRate = 2500000; usartConfig.hardwareFlow =USART_HARDWARE_FLOW_NONE ; usartConfig.mode = USART_MODE_TX_RX; usartConfig.parity = USART_PARITY_NONE; usartConfig.stopBits = USART_STOP_BIT_1; usartConfig.wordLength = USART_WORD_LEN_8B ; USART_Config(USART3,&usartConfig); USART_Enable(USART3); DMA_Disable(DMA1_Stream3); CLEAR_BIT(USART3->CTRL3, USART_CR3_DMAT); CLEAR_BIT(TMR4->CTRL1, TIM_CR1_CEN); CLEAR_BIT(TMR4->CCEN, TIM_CCER_CC1E); DMA_Disable(DMA1_Stream1); CLEAR_BIT(USART3->CTRL3, USART_CR3_DMAR); } 使用ST LL库函数编写的USART配置函数如下 void MX_USART3_UART_Init(void) { LL_USART_InitTypeDef USART_InitStruct = {0}; LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; /* Peripheral clock enable */ LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART3); LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOD); /**USART3 GPIO Configuration PD12 ------> USART3_RTS PD8 ------> USART3_TX PD9 ------> USART3_RX */ GPIO_InitStruct.Pin = RS485_TX_Pin|RS485_RX_Pin; GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; GPIO_InitStruct.Alternate = LL_GPIO_AF_7; LL_GPIO_Init(GPIOD, &GPIO_InitStruct); /* USART3 DMA Init */ /* USART3_RX Init */ LL_DMA_SetChannelSelection(DMA1, LL_DMA_STREAM_1, LL_DMA_CHANNEL_4); LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY); LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_1, LL_DMA_PRIORITY_HIGH); LL_DMA_SetMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MODE_CIRCULAR); LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_PERIPH_NOINCREMENT); LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MEMORY_INCREMENT); LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_1, LL_DMA_MDATAALIGN_BYTE); LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_1, LL_DMA_MDATAALIGN_BYTE); LL_DMA_EnableFifoMode(DMA1, LL_DMA_STREAM_1); LL_DMA_SetFIFOThreshold(DMA1, LL_DMA_STREAM_1, LL_DMA_FIFOTHRESHOLD_1_4); LL_DMA_SetMemoryBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_MBURST_SINGLE); LL_DMA_SetPeriphBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_MBURST_SINGLE); /* USART3_TX Init */ LL_DMA_SetChannelSelection(DMA1, LL_DMA_STREAM_3, LL_DMA_CHANNEL_4); LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_3, LL_DMA_DIRECTION_MEMORY_TO_PERIPH); LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_3, LL_DMA_PRIORITY_HIGH); LL_DMA_SetMode(DMA1, LL_DMA_STREAM_3, LL_DMA_MODE_CIRCULAR); LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_3, LL_DMA_PERIPH_NOINCREMENT); LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_3, LL_DMA_MEMORY_INCREMENT); LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_3, LL_DMA_PDATAALIGN_BYTE); LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_3, LL_DMA_MDATAALIGN_BYTE); LL_DMA_EnableFifoMode(DMA1, LL_DMA_STREAM_3); LL_DMA_SetFIFOThreshold(DMA1, LL_DMA_STREAM_3, LL_DMA_FIFOTHRESHOLD_1_4); LL_DMA_SetMemoryBurstxfer(DMA1, LL_DMA_STREAM_3, LL_DMA_MBURST_SINGLE); LL_DMA_SetPeriphBurstxfer(DMA1, LL_DMA_STREAM_3, LL_DMA_MBURST_SINGLE); USART_InitStruct.BaudRate = 2500000; USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B; USART_InitStruct.StopBits = LL_USART_STOPBITS_1; USART_InitStruct.Parity = LL_USART_PARITY_NONE; USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX; USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE; USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16; LL_USART_Init(USART3, &USART_InitStruct); LL_USART_ConfigAsyncMode(USART3); LL_USART_Enable(USART3); } 并且在初始化中,还需要完成对MemoryAddress,PeriphAddress的设定,自定义Encoder_txData,Encoder_rxData两个数组来用于存放UART收发的数据。 LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_3,LL_USART_DMA_GetRegAddr(USART3)); LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_3,(uint32_t)Encoder_txData); LL_DMA_SetPeriphAddress(DMA1, LL_DMA_STREAM_1,LL_USART_DMA_GetRegAddr(USART3)); LL_DMA_SetMemoryAddress(DMA1, LL_DMA_STREAM_1,(uint32_t)Encoder_rxData);
|