[APM32F4] APM32F425-伺服方案的总线编码器串口配置说明-基于APM32驱动库函数开发(DMA方式)

[复制链接]
266|1
zyz0926 发表于 2025-11-29 14:39 | 显示全部楼层 |阅读模式
#申请原创# #技术资源#

使用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);
}
并且在初始化中,还需要完成对MemoryAddressPeriphAddress的设定,自定义Encoder_txDataEncoder_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);

 楼主| zyz0926 发表于 2025-11-29 14:39 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

30

主题

62

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0