新手入门
- 积分
- 13
- 金钱
- 13
- 注册时间
- 2020-11-25
- 在线时间
- 10 小时
|
13金钱
本帖最后由 wan431 于 2021-4-17 23:50 编辑
小白刚入STM32,试写了一个DMA串口1发送的程序,串口1DMA只能发送一次。查网络资料排查了几天,未果,遂来提问,金币都在这了,很少,希望有大佬来救,工程文件也一并附在下方。
注:还必须先发给串口1数据,串口1才能利用DMA发送一次,之后就一直不能发送了。很奇怪,也没有写任何和接收有关的代码。环境:STM32F103,正点原子精英板
//这是usart.h的内容
void usart1_Init(void)
{
/* 串口1配置 115200 */
USART_InitTypeDef USART_InitStruct; // 串口配置
NVIC_InitTypeDef NVIC_InitStructure; // 中断配置
DMA_InitTypeDef DMA_InitStruct; // DMA 配置
GPIO_InitTypeDef GPIO_InitStruct;
USART_DeInit(USART1); // 寄存器恢复默认值
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 使能串口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // TX 推挽输出
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct); // PA9
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // RX上拉输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStruct); // PA10
/* 串口参数配置 */
USART_InitStruct.USART_BaudRate = BAUD_RATE; // 波特率:115200
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无流控
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 收发
USART_InitStruct.USART_Parity = USART_Parity_No; // 无校验位
USART_InitStruct.USART_StopBits = USART_StopBits_1; // 1个停止位
USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 8个数据位
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE); // 使能串口
/* 串口中断配置 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 子优先级
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 串口1中断
NVIC_Init(&NVIC_InitStructure); // 嵌套向量中断控制器初始化
USART_ITConfig(USART1, USART_IT_TC, ENABLE); // 使能串口发送中断,发送完成产生 USART_IT_TC 中断
//USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 使能串口空闲中断,接收一帧数据产生 USART_IT_IDLE 空闲中断
/* 串口DMA配置 */
DMA_DeInit(DMA1_Channel4); // DMA1 通道4,寄存器复位
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 使能 DMA1 时钟
// TX DMA1_CH4
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; // 本次是外设到内存,所以关闭内存到内存
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;// 内存数据宽度,按照字节存储
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存递增,每次串口收到数据存在内存中,下次收到自动存储在内存的下一个位置
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; // 正常模式
DMA_InitStruct.DMA_PeripheralBaseAddr = USART1_BASE + 0x04; // 外设的基地址,串口的数据寄存器
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设的数据宽度,按照字节存储,与内存的数据宽度一致
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 接收只有一个数据寄存器 RDR,所以外设地址不递增
DMA_InitStruct.DMA_Priority = DMA_Priority_High; // 优先级
DMA_InitStruct.DMA_BufferSize = 0; // 发送缓冲区的大小,初始化为0不发送
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; // 发送是方向是外设到内存,外设作为目的地
DMA_InitStruct.DMA_MemoryBaseAddr =(uint32_t)uart1SendData; // 发送内存地址,从哪里发送
DMA_Init(DMA1_Channel4, &DMA_InitStruct);
USART_DMACmd(USART1, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);// 使能DMA串口发送和接受请求
DMA_Cmd(DMA1_Channel4, DISABLE); // 禁止发送
}
void usart1_send(u8 *arr,u8 len)
{
if(len == 0) // 判断长度是否有效
return;
while (DMA_GetCurrDataCounter(DMA1_Channel4))BEEP = 1; // 检查DMA发送通道内是否还有数据
BEEP = 0;
if(arr)
memcpy(uart1SendData, arr, len);
// DMA发送数据-要先关 设置发送长度 开启DMA
DMA_Cmd(DMA1_Channel4, DISABLE);
//重新写入要传输的数据数量
DMA_SetCurrDataCounter(DMA1_Channel4, len);
//重新设置外设地址
DMA1_Channel4->CPAR = USART1_BASE + 0x04;
//重新设置内存地址
DMA1_Channel4->CMAR = (uint32_t)uart1SendData;
DMA_Cmd(DMA1_Channel4, ENABLE); // 启动DMA发送
}
void USART1_IRQHandler(void)
{
if(USART_GetFlagStatus(USART1,USART_IT_TC) != RESET)
{
USART_ClearITPendingBit(USART1,USART_IT_TC);//清除标志位
DMA_Cmd(DMA1_Channel4,DISABLE); //关闭发送通道
uart1SendFlag = 1;
}
}
//这下面是main.c的内容
#include "stm32f10x.h"
#include "delay.h"
#include "sys.h"
#include "a_bunch_init.h"
#include "usart.h"
u8 group[12] = {1,2,3,0};
int main()
{
//usart2_Init();
usart1_Init();
LED_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置中断优先级分组
while(1)
{
// if(uart2RecvFlag == 1) //接收到数据
// {
// uart2RecvFlag = 0;
// LED0 = 0;
// uart2DmaClear();//清空DMA接收通道计数
// usart1_send(group,12);
// memset(uart2RecvData,'\0',sizeof(uart2RecvData)); // 清空缓冲池
// }
usart1_send(group,12);
if(uart1SendFlag == 1) //发送完成
{
uart1SendFlag = 0;
LED1 = 0;
LED0 = 1;
delay_ms(200);
}
else
{
LED0 = 0;
LED1 = 1;
}
}
}
|
最佳答案
查看完整内容[请看2#楼]
你把发送中断发生查询函数改为 USART_GetITStatus ,然后你延时定时器没有初始化,你需要在延时使用前调用一次 delay_init()函数,我用你的工程改了这两个好了。
|