欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32F103学习笔记(四):PA9,PA10发送5路ADC数据至串口调试助手

程序员文章站 2022-04-01 16:59:50
...

目的:采集5路的电压信号,并将电压显示在oled显示屏上,同时将数据同步传输到PC机的串口调试助手中,便于对数据进行后续处理。

源代码下载链接:https://download.csdn.net/download/wang903039690/10579488

硬件:stm32f103c8t6最小系统板;复位按键;oled显示屏

首先完成对 串口(PA9,P10)以及DMA的配置,我用到了中断,最后ADC电压值处理和串口发送在中断函数中完成。

具体各个部分的原理讲解可以看看资料课本什么的,我就直接上代码了。

其实,有时候各个部分单独实现功能非常好,但是各个部分结合起来,代码就会出现乱七八糟的错误。前面一篇ADC多通道采集的代码,放到这里数据总是串行,本来1通道的值变成了4通道,等等,这次ADC没有重复采集10次,而是用了1次采集的数据,发现采集结果和10次求平均值效果不相上下,所以这次干脆只用1次,简化了代码,各个通道的值正常了。初步怀疑DMA一次传输10*5个数据的时候程序可能出了问题,自己也找不出来,干脆换了吧。

1.DMA初始化

dma.h主要定义了c文件中定义的函数,还有要发送数据的缓冲区,8字节的数组SendBuff [ ]

#ifndef __DMA__H
#define __DMA__H

#include "sys.h"

#define USART1_DR_Base 0x40013804
//#define SEND_BUF_SIZE 10	//发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.


extern u8 SendBuff[36];	//发送数据缓冲区

void MYDMA_Config(void);//配置DMA1_CHx


#endif

dma.c文件,几乎是千篇一律的套路和代码,

注意一点DMA通道的DMA缓存的大小的设置,这个非常关键,决定了后续发送至串口助手的数据大小。

#include "dma.h"
#include "led.h"
#include "delay.h"

	//DMA1的各通道配置

u8 SendBuff[36];

void MYDMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//使能DMA传输
	
	DMA_DeInit(DMA1_Channel4);   //将DMA的通道1寄存器重设为缺省值
	
	//DMA1_MEM_LEN=cndtr;
	DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;  //DMA外设基地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&SendBuff;  //DMA内存基地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  //数据传输方向,从内存读取发送到外设
	DMA_InitStructure.DMA_BufferSize = 36;  //DMA通道的DMA缓存的大小
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //数据宽度为8位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
	DMA_Init(DMA1_Channel4, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
	
	DMA_Cmd(DMA1_Channel4, ENABLE);  //使能USART1 TX DMA1 所指示的通道

}

2.USART初始化

串口的初始化也是前篇一律的,设置好最基本的参数就行。

#include "stm32f10x.h"
#include "USART1_Config.h"
#include "delay.h"


//USART1 GPIO配置,工作模式配置。115200 8-N-1

void USART1_Config(void)
{
	
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	
	//config USART1 clock
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
	
	//USART1 GPIO config
	//Configure USART1 Tx(PA9) as alternate function push-pull
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用功能推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//Configure USART1 Rx(PA10) as input floating
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮空输入模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//USART1 mode config
	USART_InitStructure.USART_BaudRate = 115200;	//波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;	//不使用硬件流
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_Parity = USART_Parity_No;	//无奇偶校验
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	
	USART_Init(USART1, &USART_InitStructure);
	USART_Cmd(USART1, ENABLE);	//使能串口

}

3.多通道(5路)电压信号采集,必须也用DMA将ADC数据传输到内存

这部分代码和之前那篇博客几乎一样,由原来传输10*5个数据变成了5个数据。获得ADC的值代码如下

//获得ADC的值	
void Get_ADC_Value()
{
	DMA_SetCurrDataCounter(DMA1_Channel1,5);				//设置DMA的传送数量为5
	DMA_Cmd(DMA1_Channel1,ENABLE);
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//使用软件转换启动功能	
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1)!=SET);			//等待DMA传送完成
	DMA_ClearFlag(DMA1_FLAG_TC1);							//清除DMA传送完成标志
	DMA_Cmd(DMA1_Channel1,DISABLE);							//停用DMA通道1
}

大框架就这么多,最后就是最关键的小细节,怎么将电压值在串口调试助手上显示出来,比如显示成:0.6286,1.7564,2.5160,3.4688,3.9666等形式。

串口调试助手是以ASCII值显示内容的,这点至关重要。我们只需要将每个电压值进行分解,比如0.6286,分离出5位数字,找到其对应的ASCII值,数字为 十进制+0x30,将ASCII值写入事先定义好的 8位 SendBuff[ ]数组中,开启串口的DMA传输就行了。我是将每个数字和字符号依次手动写入了数组中,方法笨,但效果还不错。

采集的电压是滑动变阻器两端的电压,数据波动很大,应该是电路电压不稳定的原因。如果采集单片机5V接口电压,数据波动范围尽在0.0001-0.0003mV范围

ASCII快速查阅https://blog.csdn.net/songjinshi/article/details/7868866

最后看下结果:效果还不错,达到了按下一次按键,oled显示屏和串口调试助手中都显示电压数据的结果。显示屏中只显示了最新一次显示的结果。

STM32F103学习笔记(四):PA9,PA10发送5路ADC数据至串口调试助手

STM32F103学习笔记(四):PA9,PA10发送5路ADC数据至串口调试助手