STM32CubeMX(4) —— STM32利用DMA空闲中断与Openmv通信
STM32 Cubemax(四) —— STM32利用空闲中断与Openmv通信文章目录STM32 Cubemax(四) —— STM32利用空闲中断与Openmv通信前言零、连线一、OpenMv代码二、CubeMax配置1.串口及DMA配置三、STM32单片机代码编写首先在生成usart.c中加入DMA接收中断及空闲中断创建接收结构体在stm32f4xx_it.c中编写串口3中断构造处理数据处理
STM32 Cubemax(四) —— STM32利用DMA空闲中断与Openmv通信
文章目录
前言
因为之前电赛使用到了Openmv作为摄像头,处理完数据后将数据传回STM32主控来进行后续的操作,也看了很多论坛上的文章,但总感觉代码结构都不是自己的风格,以此记录一下。
本文章STM32的配置,按照我之前的风格,都为从Cubemax配置生成。
零、连线
OpenMv | STM32 |
---|---|
TX(P4) | RX |
GND | GND |
一、OpenMv代码
首先介绍一下OpenMv这边的代码
主要使用的是ustruct这个库来作为串口的发送,注意,如果是直接用OpenMv的串口write发送,单片机这边收到的数据是不好处理的。
首先OpenMv也是单片机,要对其串口进行配置。
from pyb import UART
uart = UART(3,115200) #定义串口3变量
uart.init(115200, bits=8, parity=None, stop=1) # 这里串口设置要和后面stm32的对应
主要发送函数为如下
def sending_data(cx,cy,cw,ch):
global uart;
"""
Format C Type Python 字节数
b signed char integer 1
h short integer 2
i int integer 4
"""
data = ustruct.pack("<bbhhhhb", #格式为俩个字符俩个短整型(2字节)
0x2C, #帧头1
0x12, #帧头2
int(cx), # up sample by 4 #数据1
int(cy), # up sample by 4 #数据2
int(cw), # up sample by 4 #数据1
int(ch), # up sample by 4 #数据2
0x5B) #帧尾
uart.write(data); #必须要传入一个字节数组
二、CubeMax配置
首先简单的时钟树配置,就不在这里讲了,只要按照自己使用的单片机芯片进行配置就好,如果不会的话,可以看我之前的文章。
1.串口及DMA配置
这里主要讲讲串口及DMA的配置
这里我使用的是串口3,这里的配置要和上面OpenMv对应上
开启中断
开启接收DMA
配置完成后就可以生成代码了。
三、STM32单片机代码编写
首先在生成usart.c的MX_USART3_UART_Init中加入DMA接收中断及空闲中断
当然也可以把开启初始化放在别的地方。
/* USART3 init function */
void MX_USART3_UART_Init(void)
{
/* USER CODE BEGIN USART3_Init 0 */
/* USER CODE END USART3_Init 0 */
/* USER CODE BEGIN USART3_Init 1 */
/* USER CODE END USART3_Init 1 */
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART3_Init 2 */
// 加入DMA空闲中断
__HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart3,OpennMv_Data.RxBuffer,RXBUFFER_LEN);
/* USER CODE END USART3_Init 2 */
}
创建接收结构体
#define RXBUFFER_LEN 20
typedef struct User_USART
{
uint8_t Rx_flag;
uint8_t Rx_len; //接收长度
uint8_t frame_head[2]; //帧头
uint8_t frame_tail; //帧尾
int x,y,w,h; //处理数据
uint8_t RxBuffer[RXBUFFER_LEN]; //接收缓存
}User_USART;
在stm32f4xx_it.c中编写串口3中断
/**
* @brief This function handles USART3 global interrupt.
*/
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
// 空闲中断处理
uint32_t temp_flag = 0;
uint32_t temp;
temp_flag = __HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE);
if((temp_flag!=RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart3);
temp = huart3.Instance->SR;
temp = huart3.Instance->DR;
HAL_UART_DMAStop(&huart3);
temp = hdma_usart3_rx.Instance->NDTR;
//F1的板子 temp = hdma_usart3_rx.Instance->CNDTR;
OpennMv_Data.Rx_len = RXBUFFER_LEN-temp;
OpenMvData_Process(OpennMv_Data.RxBuffer); //按照自己需求改写这个函数
OpennMv_Data.Rx_flag = 1;
}
HAL_UART_Receive_DMA(&huart3,OpennMv_Data.RxBuffer,RXBUFFER_LEN);
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
/* USER CODE END USART3_IRQn 1 */
}
构造处理数据处理函数
//结构体初始化
void User_USART_Init(User_USART *Data)
{
for(uint8_t i=0; i < RXBUFFER_LEN; i++) Data->RxBuffer[i] = 0;
Data->frame_head[0] = 0x2C;
Data->frame_head[1] = 0x12;
Data->frame_tail = 0x5B;
Data->Rx_flag = 0;
Data->Rx_len = 0;
Data->x = 0;
Data->y = 0;
Data->w = 0;
Data->h = 0;
}
void OpenMvData_Process(uint8_t *RxBuffer)
{
//判断帧头帧尾
if(RxBuffer[0] != OpennMv_Data.frame_head[0]) return;
if(RxBuffer[1] != OpennMv_Data.frame_head[1]) return;
if(RxBuffer[10] != OpennMv_Data.frame_tail) return;
OpennMv_Data.x = (RxBuffer[3]<<8)|RxBuffer[2];
OpennMv_Data.y = (RxBuffer[5]<<8)|RxBuffer[4];
OpennMv_Data.w = (RxBuffer[7]<<8)|RxBuffer[6];
OpennMv_Data.h = (RxBuffer[9]<<8)|RxBuffer[8];
}
我在OpenMv中发送如下数据
i = i+1
sending_data(500,255,i,4)
print("is sending:",500,255,i,4)
pyb.delay(1000)
在单片机中成功接收并处理
代码总和
下面放一下usart.c和my_usart.c,my_usart.h的全部代码作为参考
uart.c
/**
******************************************************************************
* @file usart.c
* @brief This file provides code for the configuration
* of the USART instances.
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
#include "my_usart.h"
/* USER CODE BEGIN 0 */
extern User_USART OpennMv_Data;
/* USER CODE END 0 */
UART_HandleTypeDef huart3;
DMA_HandleTypeDef hdma_usart3_rx;
/* USART3 init function */
void MX_USART3_UART_Init(void)
{
/* USER CODE BEGIN USART3_Init 0 */
/* USER CODE END USART3_Init 0 */
/* USER CODE BEGIN USART3_Init 1 */
/* USER CODE END USART3_Init 1 */
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART3_Init 2 */
__HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE); //开启空闲中断
HAL_UART_Receive_DMA(&huart3,OpennMv_Data.RxBuffer,RXBUFFER_LEN); //开启DMA的接收
/* USER CODE END USART3_Init 2 */
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspInit 0 */
/* USER CODE END USART3_MspInit 0 */
/* USART3 clock enable */
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**USART3 GPIO Configuration
PB10 ------> USART3_TX
PB11 ------> USART3_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USART3 DMA Init */
/* USART3_RX Init */
hdma_usart3_rx.Instance = DMA1_Stream1;
hdma_usart3_rx.Init.Channel = DMA_CHANNEL_4;
hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart3_rx.Init.Mode = DMA_NORMAL;
hdma_usart3_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_usart3_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(uartHandle,hdmarx,hdma_usart3_rx);
/* USART3 interrupt Init */
HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
/* USER CODE BEGIN USART3_MspInit 1 */
/* USER CODE END USART3_MspInit 1 */
}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
if(uartHandle->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspDeInit 0 */
/* USER CODE END USART3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART3_CLK_DISABLE();
/**USART3 GPIO Configuration
PB10 ------> USART3_TX
PB11 ------> USART3_RX
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11);
/* USART3 DMA DeInit */
HAL_DMA_DeInit(uartHandle->hdmarx);
/* USART3 interrupt Deinit */
HAL_NVIC_DisableIRQ(USART3_IRQn);
/* USER CODE BEGIN USART3_MspDeInit 1 */
/* USER CODE END USART3_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
my_usart.c
#include "my_usart.h"
User_USART OpennMv_Data; //接收数据
//初始化函数
void User_USART_Init(User_USART *Data)
{
for(uint8_t i=0; i < RXBUFFER_LEN; i++) Data->RxBuffer[i] = 0;
Data->frame_head[0] = 0x2C;
Data->frame_head[1] = 0x12;
Data->frame_tail = 0x5B;
Data->Rx_flag = 0;
Data->Rx_len = 0;
Data->x = 0;
Data->y = 0;
Data->w = 0;
Data->h = 0;
}
void OpenMvData_Process(uint8_t *RxBuffer)
{
//检查帧头帧尾
if(RxBuffer[0] != OpennMv_Data.frame_head[0]) return;
if(RxBuffer[1] != OpennMv_Data.frame_head[1]) return;
if(RxBuffer[10] != OpennMv_Data.frame_tail) return;
OpennMv_Data.x = (RxBuffer[3]<<8)|RxBuffer[2];
OpennMv_Data.y = (RxBuffer[5]<<8)|RxBuffer[4];
OpennMv_Data.w = (RxBuffer[7]<<8)|RxBuffer[6];
OpennMv_Data.h = (RxBuffer[9]<<8)|RxBuffer[8];
}
my_usart.h
#ifndef _MY_USART_H
#define _MY_USART_H
#include "main.h"
#define RXBUFFER_LEN 20
typedef struct User_USART
{
uint8_t Rx_flag; //接收完成标志
uint8_t Rx_len; //接收长度
uint8_t frame_head[2]; //帧头
uint8_t frame_tail; //帧尾
int x,y,w,h;
uint8_t RxBuffer[RXBUFFER_LEN]; //数据存储
}User_USART;
void OpenMvData_Process(uint8_t *RxBuffer);
void User_USART_Init(User_USART *Data);
#endif
总结
在实际操作过程中,有时会出现一些小问题,如OpenMv处理数据给stm32发送时,会出现干扰信号,先检查两者有没有共地,再检查软件编写问题。
这里简单说一下为什么要用空闲中断的方法处理,在实际操作中,OpenMv发送的数据很快,而其中也会含有杂乱信息,通过空闲中断的方法,可以便于快速处理掉异常信息。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)