IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32复习笔记(十) —— USART(DMA)发送数据 -> 正文阅读

[嵌入式]STM32复习笔记(十) —— USART(DMA)发送数据

STM32复习笔记(十) —— USART(DMA)发送数据

1.USART 框图 (STM32F10xxx参考手册 图248 USART框图)
SSS10.001
SSS10.002
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 各中断事件被连接到同一个中断向量,设置对应的使能控制位,即可产生对应中断
SSS10.003
2.帧数据格式 (传输时低位先行)

数据帧长度 (位)奇偶校验使能USART 帧
8起始位-8位数据-停止位
8起始位-7位数据-奇偶校验位-停止位
9起始位-9位数据-停止位
9起始位-8位数据-奇偶校验位-停止位

偶校验:数据位相加,结果为偶数校验位置0,结果为奇数校验位置1

奇校验:数据位相加,结果为奇数校验位置0,结果为偶数校验位置1

使能校验后,将自动生成并配置校验位数据

3.本例程软件设计思路

不使用中断,直接发送数据,不接收数据

于 main.c 中编写代码

#include "stm32f10x.h"

/**
	* @ 简  介:USART1 全双工模式引脚配置
	* @ 参  数:无
	* @ 返回值:无
	*/
static void USART1_GPIO_Config(void)
{
	uint32_t tempreg = 0x00;
	
	/* 开启 GPIOA 时钟,Tx/PA9 Rx/PA10 */
	RCC->APB2ENR |= (uint16_t)0x04;
	
	tempreg  = GPIOA->CRH;
	
	/* Tx/PA9  复用推挽输出,10MHz */
	/* Rx/PA10 浮空输入 */
	tempreg &= (uint32_t)0xFFFFF00F;
	tempreg |= (uint32_t)0x00000490;
	
	GPIOA->CRH = tempreg;
}

void USART1_Config(void)
{
	/* USART1 引脚配置 */
	USART1_GPIO_Config();
	
	/* 开启 USART1 时钟 */
	RCC->APB2ENR |= ((uint16_t)0x01 << 14);
	
	/* 配置波特率 57600 */
	USART1->BRR = ((uint16_t)0x04e2);
	
	/* 配置停止位 1 */
	USART1->CR2 &= ~((uint32_t)0x03 << 12);

	/* 配置字长 8,校验位,收发使能 */
	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 模块 */
	USART1->CR1 |= ((uint16_t)0x01 << 13);
}

int main(void)
{
	/* USART1 配置 */
	USART1_Config();
	
	/* 调用固件库函数发送一个字节数据 */
	USART_SendData(USART1,0xA5);
	
	/* 等待发送完成 */
	while(0 == (USART1->SR & (uint16_t)0x80));
	
	while(1);
}

点击编译,如无错误可进入仿真界面
SSS10.004
打开串口窗口
SSS10.005
右击空白处,选择 HEX Mode (发送的数据为 0xA5)
SSS10.006
点击运行
SSS10.007
串口窗口接收到发送的数据,与预想结果一致

停止并退出仿真界面,修改程序为使用中断发送数据

于 main.c 中编写代码

#define  USER_USART1_PRIORITY    4

const uint8_t UsartSendBuff[4] = {0x10,0x00,0x00,0x10};

/**
  * @ 简  介:设置 NVIC 优先级分组为组4
	* @ 参  数:无
	* @ 返回值:无
	*/
void NVIC_Priority_Group_Config(void)
{
	/* 设置优先级分组 4 (优先级为 0 - 15) */
	SCB->AIRCR = (uint32_t)0x05FA0300;
}

static void USART1_NVIC_Config(void)
{
	/* USART1 作为中断源,配置优先级 USER_USART1_PRIORITY
	   N = 37,M = 37/4 = 9,byte offset = 37%4 = 1
	   IPR9 and byte offset = 1 */
	NVIC->IP[37] = ((uint8_t)4 << 4);
	
	/* 使能 USART1 中断 */
	NVIC->ISER[1]|=((uint32_t)0x01 << 5);
}

/**
	* @ 简  介:USART1 全双工模式引脚配置
	* @ 参  数:无
	* @ 返回值:无
	*/
static void USART1_GPIO_Config(void)
{
	uint32_t tempreg = 0x00;
	
	/* 开启 GPIOA 时钟,Tx/PA9 Rx/PA10 */
	RCC->APB2ENR |= (uint16_t)0x04;
	
	tempreg  = GPIOA->CRH;
	
	/* Tx/PA9  复用推挽输出,10MHz */
	/* Rx/PA10 浮空输入 */
	tempreg &= (uint32_t)0xFFFFF00F;
	tempreg |= (uint32_t)0x00000490;
	
	GPIOA->CRH = tempreg;
}

void USART1_Config(void)
{
	/* USART1 引脚配置 */
	USART1_GPIO_Config();
	
	/* 开启 USART1 时钟 */
	RCC->APB2ENR |= ((uint16_t)0x01 << 14);
	
	/* 配置波特率 57600 */
	USART1->BRR = ((uint16_t)0x04e2);
	
	/* 配置停止位 1 */
	USART1->CR2 &= ~((uint32_t)0x03 << 12);

	/* 配置字长 8 */
	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 中断配置 */
	USART1_NVIC_Config();
	
	/* 使能 USART1 模块 */
	USART1->CR1 |= ((uint16_t)0x01 << 13);
}

int main(void)
{
	/* 配置 NVIC 优先级分组 */
	NVIC_Priority_Group_Config();
	
	/* USART1 配置 */
	USART1_Config();

	/* 使能 USART1 发送中断 */
	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 发送中断 */
			USART1->CR1 &= ~((uint32_t)0x01 << 7);
		}
	}
}

点击编译,如无错误进入仿真界面,点击运行
SSS10.008
串口窗口接收到通过中断发送的数据,与预想结果一致

停止并退出仿真界面,修改程序为使用 DMA传输(MTP) 发送数据

于 main.c 中编写代码

const uint8_t UsartSendBuff[8] = 
{
	0x02,0x00,0x02,0x01,
	0x10,0x00,0x00,0x10
};

/**
	* @ 简  介:USART1 全双工模式引脚配置
	* @ 参  数:无
	* @ 返回值:无
	*/
static void USART1_GPIO_Config(void)
{
	uint32_t tempreg = 0x00;
	
	/* 开启 GPIOA 时钟,Tx/PA9 Rx/PA10 */
	RCC->APB2ENR |= (uint16_t)0x04;
	
	tempreg  = GPIOA->CRH;
	
	/* Tx/PA9  复用推挽输出,10MHz */
	/* Rx/PA10 浮空输入 */
	tempreg &= (uint32_t)0xFFFFF00F;
	tempreg |= (uint32_t)0x00000490;
	
	GPIOA->CRH = tempreg;
}

void USART1_Config(void)
{
	/* USART1 引脚配置 */
	USART1_GPIO_Config();
	
	/* 开启 USART1 时钟 */
	RCC->APB2ENR |= ((uint16_t)0x01 << 14);
	
	/* 配置波特率 57600 */
	USART1->BRR = ((uint16_t)0x04e2);
	
	/* 配置停止位 1 */
	USART1->CR2 &= ~((uint32_t)0x03 << 12);

	/* 配置字长 8 */
	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 模块 */
	USART1->CR1 |= ((uint16_t)0x01 << 13);
}

static void USART1_DMA_Config(void)
{
	/* 开启 DMA1 时钟 */
	RCC->AHBENR |= ((uint16_t)0x01 << 0);
	
	/* 清除 CCR 寄存器 */
	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 配置 */
	USART1_Config();
	
	/* DMA 配置 */
	USART1_DMA_Config();
	
	/* DMA 使能发送 */
	USART1->CR3 |= ((uint32_t)0x01 << 7);
	
	while(1);
}

点击编译,如无错误进入仿真界面,点击运行
SSS10.009
串口窗口接收到通过DMA发送的数据,与预想结果一致

4.本篇总结

共设计了三个例程:

1)串口直接发送数据
2)串口中断发送数据
3)使用 DMA 传输数据

经验证,程序运行结果均与预想一致

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-12 23:37:07  更:2021-10-12 23:39:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:44:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码