STM32F103配置
1-0 串口配置
void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能USART1时钟
RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, ENABLE); //复位串口1
RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, DISABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //TX PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//RX PA.10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART1, &USART_InitStructure); //初始化串口1
// USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断 ???
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 空闲中断,打开接收中断。
USART_Cmd(USART1, ENABLE); //使能串口1
usart1_dma_tx_init();
usart1_dma_rx_init();
}
1-1 DMA发送模式配置
static void usart1_dma_tx_init(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)usart1_tx_buff;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 0;/*避免初始化发送数据,设置为0*/
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
DMA_Cmd(DMA1_Channel4, ENABLE);
}
1-2 通过DMA传输数据到USART1的发送寄存器
// 用于通过DMA传输数据到USART1的发送寄存器
uint8_t usart1_dma_tx_data(void* buffer, uint16_t data_lenth)
{
if(data_lenth < 1)// 判断长度是否有效
{
return ERROR;
}
while (DMA_GetCurrDataCounter(DMA1_Channel4));// 检查DMA发送通道内是否还有数据
if(NULL == buffer)//指针判空
{
return ERROR;
}
USART1_state.txc = RESET; // 表示发送未完成。
// 使用memcpy函数将buffer中的数据复制到usart1_tx_buff中。
// 复制的长度为data_lenth和USART1_TX_BUFF_MAX_LENTH中较小的值。这是为了防止数据溢出。
memcpy(usart1_tx_buff, buffer,((data_lenth > USART1_TX_BUFF_MAX_LENTH) ? USART1_TX_BUFF_MAX_LENTH:data_lenth));
DMA_Cmd(DMA1_Channel4, DISABLE); //DMA发送数据-要先关 ,以确保设置发送长度之前DMA传输已经停止。
DMA_SetCurrDataCounter(DMA1_Channel4, data_lenth);// 设置DMA1_Channel4的发送长度为data_lenth。
DMA_Cmd(DMA1_Channel4, ENABLE);// 启用DMA1_Channel4,以启动DMA传输
return SUCCESS;
}
1-3 串口数据发送
将usart1_dma_tx_data()函数放在main函数中或者中断处理函数中即可,如下所示:文章来源地址https://www.toymoban.com/news/detail-625137.html
void main()
{
uint8_t data_array[8];
data_array[0] = 0x12;
data_array[1] = 0x34;
data_array[2] = (int)Encoder & 0xFF;
data_array[3] = ((int)Encoder >> 8) & 0xFF;
data_array[4] = (int)Adc & 0xFF;
data_array[5] = ((int)Adc >> 8) & 0xFF;
data_array[6] = 0x56;
data_array[7] = 0x78;
usart1_dma_tx_data(data_array, 8);
}
2-1 DMA接收模式配置
#define USART1_RX_BUFF_MAX_LENTH 200 //定义最大接收字节数 200
#define USART1_TX_BUFF_MAX_LENTH 200
static void usart1_dma_rx_init(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; // 初始化外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)usart1_rx_buff; // 缓存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 外设作为数据来源
DMA_InitStructure.DMA_BufferSize = USART1_RX_BUFF_MAX_LENTH; // 缓存容量
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;// 外设字节宽度
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 内存字节宽度
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 正常模式,即满了就不在接收了,而不是循环存储
DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 优先级很高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 内存与外设通信,而非内存到内存
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE);
}
2-2 串口结束中断
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)/*空闲中断接收*/
{
u8 data_lenth = 0 ;
DMA_Cmd(DMA1_Channel5, DISABLE);// 关闭DMA ,防止干扰
USART_ReceiveData( USART1 );
data_lenth = USART1_RX_BUFF_MAX_LENTH - DMA_GetCurrDataCounter(DMA1_Channel5);//获得接收到的字节数
DMA_SetCurrDataCounter(DMA1_Channel5, USART1_RX_BUFF_MAX_LENTH);// 重新赋值计数值,必须大于等于最大可能接收到的数据帧数目
DMA_Cmd(DMA1_Channel5, ENABLE);
USART1_state.rxc = SET; //设置接收完成标志
my_usmart_scan(usart1_rx_buff,data_lenth); //配置自己的接收处理函数//执行usmart扫描
memset(usart1_rx_buff, 0, USART1_RX_BUFF_MAX_LENTH); //清空接收缓存区
USART_ClearITPendingBit(USART1, USART_IT_IDLE); // Clear IDLE interrupt flag bit
}
if(USART_GetITStatus(USART1,USART_IT_TC) != RESET) //发送完成标记
{
DMA_Cmd(DMA1_Channel4, DISABLE); // 关闭DMA
DMA_SetCurrDataCounter(DMA1_Channel4,RESET); // 清除数据长度
USART1_state.txc = SET; // 设置发送完成标志
USART_ClearITPendingBit(USART1, USART_IT_TC); // 清除完成标记
}
}
2-3 对串口接收的数据进行处理
void my_usmart_scan(uint8_t * data_array,uint8_t data_lenth)
{
if(SET == USART1_state.rxc)//串口接收完成标志位
{
if(data_array[0] == 0x2D && data_array[1] == 0x01 && data_array[5] == 0x56 && data_array[6] == 0x78) // 判断帧头1和2是否正确、帧尾1和2是否正确
{
float value = 0;
int16_t sign = 1;
if(data_array[2] == 0x45) // 符号位判断
{
sign = -1;
}
value = (data_array[4] << 8) + data_array[3];
action = sign * value; // 接收的数据
}
USART1_state.rxc = RESET;//状态寄存器清空
}
}
python上位机程序
# 从串口接收的数据为:编码器(整型)、角位移传感器(浮点型)
def read_serial_one_data_encoder_adc(ser):
global receive_result
BUF_SIZE = 8
buf = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
c1 = ib = flag = 0
while True:
R = ser.read(1)
# print("data", R)
if R == b'':
print("Read Fail")
ser.close()
break
c = int.from_bytes(R, byteorder='big')
# print("data", c)
if flag > 0:
if ib < BUF_SIZE:
buf[ib] = c
ib += 1
if ib == 8:
if buf[6] == 0x56 and buf[7] == 0x78:
Encoder = (buf[3] << 8) + buf[2]
Adc= (buf[5] << 8) + buf[4]
receive_result = [Encoder, Adc]
break
else:
print("CRC Fail")
flag = 0
if flag == 0:
if c1 == 0x12 and c == 0x34:
flag = 1
ib = 2
c1 = c
return receive_result
def run_play():
result = [0, 0]
action = bytearray([0x12, 0x34, 0x00, 0x00, 0x00, 0x56, 0x78])
ser = serial.Serial( # 下面这些参数根据情况修改
port='COM8', # 串口
baudrate=921600, # 波特率
timeout=None,
parity=serial.PARITY_ODD, #
stopbits=serial.STOPBITS_ONE,
bytesize=8
)
if ser.isOpen(): # 判断串口是否打开
print("open success")
for i in range(1000000):
result2 = read_serial_one_data_encoder_adc(ser) # /************从串口接收数据函数**************/
print("result2=",result)
ser.write(action) # 使用DMA需要多个字节一起发送 /************往串口发送数据函数**************/
if __name__ == '__main__':
run_play()
3 完整程序
#include "sys.h"
#include "usart.h"
#include <string.h>
#include <math.h>
#include <stdio.h>
uint16_t Res;
float action;
uint16_t check_flag;
#define USART1_RX_BUFF_MAX_LENTH 200 //定义最大接收字节数 200
#define USART1_TX_BUFF_MAX_LENTH 200
uint8_t ReceiveBuff[RECEIVEBUFF_SIZE];
static uint8_t usart1_tx_buff[USART1_TX_BUFF_MAX_LENTH];
uint8_t usart1_rx_buff[USART1_RX_BUFF_MAX_LENTH];
typedef struct
{
uint8_t rxc;
uint8_t txc;
}uart_state_t;
uart_state_t USART1_state;
//
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h" //ucos 使用
#endif
//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
重定义fputc函数
//int fputc(int ch, FILE *f)
//{
// while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
// USART1->DR = (u8) ch;
// return ch;
//}
#endif
#if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记
void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能USART1时钟
RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, ENABLE); //复位串口1
RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, DISABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //TX PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//RX PA.10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART1, &USART_InitStructure); //初始化串口1
// USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断 ???
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 空闲中断,打开接收中断。
USART_Cmd(USART1, ENABLE); //使能串口1
usart1_dma_tx_init();
usart1_dma_rx_init();
}
static void usart1_dma_tx_init(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)usart1_tx_buff;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 0;/*避免初始化发送数据,设置为0*/
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
DMA_Cmd(DMA1_Channel4, ENABLE);
}
// 用于通过DMA传输数据到USART1的发送寄存器
uint8_t usart1_dma_tx_data(void* buffer, uint16_t data_lenth)
{
if(data_lenth < 1)// 判断长度是否有效
{
return ERROR;
}
while (DMA_GetCurrDataCounter(DMA1_Channel4));// 检查DMA发送通道内是否还有数据
if(NULL == buffer)//指针判空
{
return ERROR;
}
USART1_state.txc = RESET; // 表示发送未完成。
// 使用memcpy函数将buffer中的数据复制到usart1_tx_buff中。
// 复制的长度为data_lenth和USART1_TX_BUFF_MAX_LENTH中较小的值。这是为了防止数据溢出。
memcpy(usart1_tx_buff, buffer,((data_lenth > USART1_TX_BUFF_MAX_LENTH) ? USART1_TX_BUFF_MAX_LENTH:data_lenth));
DMA_Cmd(DMA1_Channel4, DISABLE); //DMA发送数据-要先关 ,以确保设置发送长度之前DMA传输已经停止。
DMA_SetCurrDataCounter(DMA1_Channel4, data_lenth);// 设置DMA1_Channel4的发送长度为data_lenth。
DMA_Cmd(DMA1_Channel4, ENABLE);// 启用DMA1_Channel4,以启动DMA传输
return SUCCESS;
}
static void usart1_dma_rx_init(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; // 初始化外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)usart1_rx_buff; // 缓存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 外设作为数据来源
DMA_InitStructure.DMA_BufferSize = USART1_RX_BUFF_MAX_LENTH; // 缓存容量
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;// 外设字节宽度
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 内存字节宽度
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 正常模式,即满了就不在接收了,而不是循环存储
DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 优先级很高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 内存与外设通信,而非内存到内存
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE);
}
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)/*空闲中断接收*/
{
u8 data_lenth = 0 ;
DMA_Cmd(DMA1_Channel5, DISABLE);// 关闭DMA ,防止干扰
USART_ReceiveData( USART1 );
data_lenth = USART1_RX_BUFF_MAX_LENTH - DMA_GetCurrDataCounter(DMA1_Channel5);//获得接收到的字节数
DMA_SetCurrDataCounter(DMA1_Channel5, USART1_RX_BUFF_MAX_LENTH);// 重新赋值计数值,必须大于等于最大可能接收到的数据帧数目
DMA_Cmd(DMA1_Channel5, ENABLE);
USART1_state.rxc = SET; //设置接收完成标志
my_usmart_scan(usart1_rx_buff,data_lenth); //配置自己的接收处理函数//执行usmart扫描
memset(usart1_rx_buff, 0, USART1_RX_BUFF_MAX_LENTH); //清空接收缓存区
USART_ClearITPendingBit(USART1, USART_IT_IDLE); // Clear IDLE interrupt flag bit
}
if(USART_GetITStatus(USART1,USART_IT_TC) != RESET) //发送完成标记
{
DMA_Cmd(DMA1_Channel4, DISABLE); // 关闭DMA
DMA_SetCurrDataCounter(DMA1_Channel4,RESET); // 清除数据长度
USART1_state.txc = SET; // 设置发送完成标志
USART_ClearITPendingBit(USART1, USART_IT_TC); // 清除完成标记
}
}
///********************************************************
//Function: void my_usmart_scan(uint8_t * data_array,uint8_t data_lenth)
//Description:处理接收数据
//Input:
//Output:
//Others:
//*********************************************************/
void my_usmart_scan(uint8_t * data_array,uint8_t data_lenth)
{
if(SET == USART1_state.rxc)//串口接收完成标志位
{
if(data_array[0] == 0x2D && data_array[1] == 0x01 && data_array[5] == 0x56 && data_array[6] == 0x78) // 判断帧头是否正确、判断奇偶校验位是否正确 || USART_RX_BUF[1] == check_flag
{
float value = 0;
int16_t sign = 1;
if(data_array[2] == 0x45)
{
sign = -1;
}
value = (data_array[4] << 8) + data_array[3];
action = sign * value;
}
USART1_state.rxc = RESET;//状态寄存器清空
}
}
文章来源:https://www.toymoban.com/news/detail-625137.html
到了这里,关于stm32和python实现DMA+串口数据收发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!