STM32复习笔记(十) —— USART(DMA)发送数据
1.USART 框图 (STM32F10xxx参考手册 图248 USART框图) USART 实际上存在两个数据寄存器 and 两个移位寄存器:
发送数据时,将数据存入数据寄存器,由移位寄存器发送出去; 接收数据时,数据通过移位寄存器接收,再送入到数据寄存器。
编程使用时,数据收发只需读写数据寄存器 USART_DR:
发送数据时,将数据写入 USART_DR 寄存器; 接收数据时,从 USART_DR 寄存器读取数据。
此处只演示 USART 异步通信,外部引脚仅需使用 Tx and Rx and 收发设备共地线
其内部存在波特率发生器,设备间通信时收发双方波特率需一致
Tx / Rx 波特率 = fck / (16 * USARTDIV)
Fck 为 USART 时钟源,USARTDIV 为时钟源分频系数 (实际时钟的提供需由时钟源先进行 USARTDIV 分频,再经过16分频,此也即为上述公式的原理),编程使用时由波特率寄存器间接设置 USARTDIV 值
如需 USART1 设置波特率 115200,其中USART1 时钟源为 PCLK2(72MHz)
115200 = 72MHz / (16*USARTDIV) => USARTDIV = 39.0625
将 39.0625 分为整数和小数分别配置到波特率寄存器 DIV_Mantissa and DIV_Fraction 中
十进制转十六进制 (如:39.0625D = 271H):
整数部分:除基取余,高位在前
39 / 16 = 2 … 7,即39D = 27H
小数部分:乘基取整,高位在前
0.0625 * 16 = 1,即 0.625D = 1H
USARTDIV = 39.0625,DIV_Mantissa = 0x027,DIV_Fraction = 0x1,即 USART_BRR = 0x271
USART 各中断事件被连接到同一个中断向量,设置对应的使能控制位,即可产生对应中断 2.帧数据格式 (传输时低位先行)
数据帧长度 (位) | 奇偶校验使能 | USART 帧 |
---|
8 | 否 | 起始位-8位数据-停止位 | 8 | 否 | 起始位-7位数据-奇偶校验位-停止位 | 9 | 是 | 起始位-9位数据-停止位 | 9 | 是 | 起始位-8位数据-奇偶校验位-停止位 |
偶校验:数据位相加,结果为偶数校验位置0,结果为奇数校验位置1
奇校验:数据位相加,结果为奇数校验位置0,结果为偶数校验位置1
使能校验后,将自动生成并配置校验位数据
3.本例程软件设计思路
不使用中断,直接发送数据,不接收数据
于 main.c 中编写代码
#include "stm32f10x.h"
static void USART1_GPIO_Config(void)
{
uint32_t tempreg = 0x00;
RCC->APB2ENR |= (uint16_t)0x04;
tempreg = GPIOA->CRH;
tempreg &= (uint32_t)0xFFFFF00F;
tempreg |= (uint32_t)0x00000490;
GPIOA->CRH = tempreg;
}
void USART1_Config(void)
{
USART1_GPIO_Config();
RCC->APB2ENR |= ((uint16_t)0x01 << 14);
USART1->BRR = ((uint16_t)0x04e2);
USART1->CR2 &= ~((uint32_t)0x03 << 12);
USART1->CR1 &= ~((uint16_t)0x01 << 12);
USART1->CR1 &= ~((uint16_t)0x03 << 9);
USART1->CR1 |= ((uint16_t)0x01 << 3);
USART1->CR1 &= ~((uint16_t)0x01 << 2);
USART1->CR1 |= ((uint16_t)0x01 << 13);
}
int main(void)
{
USART1_Config();
USART_SendData(USART1,0xA5);
while(0 == (USART1->SR & (uint16_t)0x80));
while(1);
}
点击编译,如无错误可进入仿真界面 打开串口窗口 右击空白处,选择 HEX Mode (发送的数据为 0xA5) 点击运行 串口窗口接收到发送的数据,与预想结果一致
停止并退出仿真界面,修改程序为使用中断发送数据
于 main.c 中编写代码
#define USER_USART1_PRIORITY 4
const uint8_t UsartSendBuff[4] = {0x10,0x00,0x00,0x10};
void NVIC_Priority_Group_Config(void)
{
SCB->AIRCR = (uint32_t)0x05FA0300;
}
static void USART1_NVIC_Config(void)
{
NVIC->IP[37] = ((uint8_t)4 << 4);
NVIC->ISER[1]|=((uint32_t)0x01 << 5);
}
static void USART1_GPIO_Config(void)
{
uint32_t tempreg = 0x00;
RCC->APB2ENR |= (uint16_t)0x04;
tempreg = GPIOA->CRH;
tempreg &= (uint32_t)0xFFFFF00F;
tempreg |= (uint32_t)0x00000490;
GPIOA->CRH = tempreg;
}
void USART1_Config(void)
{
USART1_GPIO_Config();
RCC->APB2ENR |= ((uint16_t)0x01 << 14);
USART1->BRR = ((uint16_t)0x04e2);
USART1->CR2 &= ~((uint32_t)0x03 << 12);
USART1->CR1 &= ~((uint16_t)0x01 << 12);
USART1->CR1 &= ~((uint16_t)0x03 << 9);
USART1->CR1 |= ((uint16_t)0x01 << 3);
USART1->CR1 &= ~((uint16_t)0x01 << 2);
USART1_NVIC_Config();
USART1->CR1 |= ((uint16_t)0x01 << 13);
}
int main(void)
{
NVIC_Priority_Group_Config();
USART1_Config();
USART1->CR1 |= ((uint32_t)0x01 << 7);
while(1);
}
void USART1_IRQHandler(void)
{
static uint16_t i = 0;
if(0 != (USART1->SR & (uint16_t)0x80))
{
USART_SendData(USART1,(uint16_t)UsartSendBuff[i++]);
if(i >= sizeof(UsartSendBuff))
{
i = 0;
USART1->CR1 &= ~((uint32_t)0x01 << 7);
}
}
}
点击编译,如无错误进入仿真界面,点击运行 串口窗口接收到通过中断发送的数据,与预想结果一致
停止并退出仿真界面,修改程序为使用 DMA传输(MTP) 发送数据
于 main.c 中编写代码
const uint8_t UsartSendBuff[8] =
{
0x02,0x00,0x02,0x01,
0x10,0x00,0x00,0x10
};
static void USART1_GPIO_Config(void)
{
uint32_t tempreg = 0x00;
RCC->APB2ENR |= (uint16_t)0x04;
tempreg = GPIOA->CRH;
tempreg &= (uint32_t)0xFFFFF00F;
tempreg |= (uint32_t)0x00000490;
GPIOA->CRH = tempreg;
}
void USART1_Config(void)
{
USART1_GPIO_Config();
RCC->APB2ENR |= ((uint16_t)0x01 << 14);
USART1->BRR = ((uint16_t)0x04e2);
USART1->CR2 &= ~((uint32_t)0x03 << 12);
USART1->CR1 &= ~((uint16_t)0x01 << 12);
USART1->CR1 &= ~((uint16_t)0x03 << 9);
USART1->CR1 |= ((uint16_t)0x01 << 3);
USART1->CR1 &= ~((uint16_t)0x01 << 2);
USART1->CR1 |= ((uint16_t)0x01 << 13);
}
static void USART1_DMA_Config(void)
{
RCC->AHBENR |= ((uint16_t)0x01 << 0);
DMA1_Channel4->CCR &= (uint32_t)0xffff8000;
DMA1_Channel4->CCR |= ((uint32_t)0x01 << 4);
DMA1_Channel4->CCR |= ((uint32_t)0x01 << 7);
DMA1_Channel4->CCR |= ((uint32_t)0x01 << 12);
DMA1_Channel4->CCR &= ~((uint32_t)0x01 << 14);
DMA1_Channel4->CNDTR = ((uint32_t)sizeof(UsartSendBuff));
DMA1_Channel4->CPAR = (uint32_t)(USART1_BASE + 0x04);
DMA1_Channel4->CMAR = (uint32_t)UsartSendBuff;
DMA1_Channel4->CCR |= ((uint32_t)0x01 << 0);
}
int main(void)
{
USART1_Config();
USART1_DMA_Config();
USART1->CR3 |= ((uint32_t)0x01 << 7);
while(1);
}
点击编译,如无错误进入仿真界面,点击运行 串口窗口接收到通过DMA发送的数据,与预想结果一致
4.本篇总结
共设计了三个例程:
1)串口直接发送数据 2)串口中断发送数据 3)使用 DMA 传输数据
经验证,程序运行结果均与预想一致
|