写在前面

我们的购物机器人要完成识别,控制,抓取等动作的话,仅靠一块嵌入式芯片是远远不够的,因此我们的购物机器人还搭载了树莓派。我将在这篇博客里面分享树莓派和嵌入式芯片(以STM32F427IIH6为例)通过DMA+USART进行通信的方法

树莓派

树莓派端我们需要找到USB端口设备,我的树莓派上是CHASSIS_SERIAL_PORT = '/dev/ttyUSB0',获得了端口设备之后就可以开始调库了,这也是python语言的拿手好戏。这次我们用的库是serial,我们需要这个库里的函数

  • 串口初始化self.port_chassis = serial.Serial(CHASSIS_SERIAL_PORT, 9600, timeout=1)
  • 发送数据self.port_chassis.write((direction + str(distance)).encode())
  • 读取数据self.port_chassis.readline().decode()
  • 流初始化
    self.port_chassis.flushInput();self.port_chassis.flushOutput()

有了上面几个函数之后,就可以开始写python脚本啦,结合代码来进行分析
首先是类的初始化函数,目的主要是初始化USART(UART)的波特率

    def __init__(self):
        print("move init finish")
        self.time1 = time.time()
        self.time2 = time.time()
        self.flag = False
        self.port_chassis = serial.Serial(CHASSIS_SERIAL_PORT, 9600, timeout=1)
        # print('port_chassis is :' + self.port_chassis.is_Open())
        self.port_chassis.flushInput()
        self.port_chassis.flushOutput()

接下来就是发送数据,我们的购物机器人是通过树莓派做为整个的 “大脑”,是由树莓派里的python脚本给底盘发送指令,所以这个函数就是python让底盘移动distance个格子的函数,这个函数里面也是通过USART(UART)给底盘发送指令的,所用函数就是self.port_chassis.write((direction + str(distance)).encode())

    def move_by_grid(self, direction, distance=''):
        # print('move by grid')
        self.port_chassis.write((direction + str(distance)).encode())
        self.time1 = time.time()
        print(direction + str(distance))
        self.wait_for_act_end_signal_chassis(direction, distance)

最后是接收数据,既然树莓派要控制底盘,树莓派自然也要接收到底盘回传的数据,这里用到的USART(UART)接收数据函数是self.port_chassis.readline().decode(),sig就是树莓派接收到的USART(UART)数据,用户就可以对其做处理啦

    def wait_for_act_end_signal_chassis(self, ret=None, distance=0):
        print('waiting chassis...')
        while True:
            sig = self.port_chassis.readline().decode()

            # print(self.time2 - self.time1)

            sig = sig[0:2]
            print(sig)
            #
            if sig == 'HI':
                self.time2 = time.time()
                print(self.time2 - self.time1)
                if self.time2 - self.time1 < 1.0 and self.flag == False and distance == 1:
                    print('1 step deal error')
                    self.flag = True
                    if (ret == dir_up or ret == dir_back):
                        self.move_by_grid(ret, 1)
                    else:

STM32F427IIH6

在嵌入式芯片STM32F427IIH6里,我们首先要打开芯片的DMA功能,然后进行USART(UART)的初始化,最后设置USART(UART)的回调函数即可
首先进行DMA的初始化,在这些初始化里面完成的就是DMA时钟的使能和DMA中断的使能

void MX_DMA_Init(void) 
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA1_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
  /* DMA1_Stream1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
  /* DMA1_Stream3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
  /* DMA1_Stream6_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
  /* DMA2_Stream1_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
  /* DMA2_Stream6_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);

}

DMA使能完成之后就要进行USART(UART)的基本配置了,这里我设置的就是波特率9600(各个USART(UART)波特率初始化大同小异,因此在这里只放了usart6的初始化,其他类似,不做赘述)

void MX_USART6_UART_Init(void)
{

  huart6.Instance = USART6;
  huart6.Init.BaudRate = 9600;
  huart6.Init.WordLength = UART_WORDLENGTH_8B;
  huart6.Init.StopBits = UART_STOPBITS_1;
  huart6.Init.Parity = UART_PARITY_NONE;
  huart6.Init.Mode = UART_MODE_TX_RX;
  huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart6.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart6) != HAL_OK)
  {
    Error_Handler();
  }

}

完成了芯片级的配置之后,就要开始配置用户自己需求的USART(UART)功能了,简单点来说就是就是设置回调函数,并且编写回调函数内容
void USR_UartInit(void)中主要是打开USART(UART)的DMA接收功能,并且开启USART(UART)接收中断HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)就是我们的回调函数,uart6Rx[1024],uart7Rx[1024],uart8Rx[1024]这3个数组就是STM32F427IIH6的3个(USART6,UART7,UART8)USART(UART)接收到的数组数据 啦,接下来用户就可以对其做处理啦。

void USR_UartInit(void)
{
    test1++;

    uart8RxLength = 0;   
    HAL_UART_Receive_DMA(&huart8, uart8Rx, buffer_size);
    uart7RxLength = 0;   
    HAL_UART_Receive_DMA(&huart7, uart7Rx, buffer_size);
    uart6RxLength = 0;   
    HAL_UART_Receive_DMA(&huart6, uart6Rx, buffer_size);    

    __HAL_UART_ENABLE_IT(&huart8, UART_IT_IDLE);     
    __HAL_UART_ENABLE_IT(&huart7, UART_IT_IDLE);   
    __HAL_UART_ENABLE_IT(&huart6, UART_IT_IDLE);   
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{

    HAL_UART_Receive_DMA(&huart8, uart8Rx, buffer_size); 
    HAL_UART_Receive_DMA(&huart7, uart7Rx, buffer_size);
    HAL_UART_Receive_DMA(&huart6, uart6Rx, buffer_size);
    __HAL_DMA_ENABLE(&hdma_uart8_rx); 
    __HAL_DMA_ENABLE(&hdma_uart7_rx);
    __HAL_DMA_ENABLE(&hdma_usart6_rx);
    test2++;
}
uint8_t RxLenHi, RxLenlo;  
void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
{
    __HAL_UART_CLEAR_IDLEFLAG(huart);

        if( huart == &huart8)
        {
            test3++;
            HAL_UART_Receive_DMA(&huart8, uart8Rx, buffer_size);  

            uart8RxLength = buffer_size-__HAL_DMA_GET_COUNTER(&hdma_uart8_rx);     
            if(uart8Rx[0]=='@'
            &&uart8Rx[1]=='c'
            &&uart8Rx[2]=='m'
            &&uart8Rx[3]=='d') 
            {
                if(!SERDEB_CmdValid())
                    SERDEB_PushCmd(uart8Rx, uart8RxLength);
            }
            __HAL_DMA_DISABLE(&hdma_uart8_rx);
            HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_8);    
        }

          if( huart == &huart7)
        {        
            __HAL_DMA_DISABLE(&hdma_uart7_rx);  
            HAL_UART_Receive_DMA(&huart7, uart7Rx, buffer_size); 
            __HAL_DMA_DISABLE(&hdma_uart7_rx);
        }

        if( huart == &huart6)
        {
            __HAL_DMA_DISABLE(&hdma_usart6_rx);
            HAL_UART_Receive_DMA(&huart6, uart6Rx, buffer_size); 
            __HAL_DMA_DISABLE(&hdma_usart6_rx);
        }

}

至此完成了双工通信的基本配置,接下来我会在另外一篇博客中具体讲解如何处理接收到的数据,敬请期待~


(づ ̄3 ̄)づ╭❤~一键三连,这次一定(๑•̀ㅂ•́)و✧