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

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

硬件: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显示屏和串口调试助手中都显示电压数据的结果。显示屏中只显示了最新一次显示的结果。

猜你喜欢

转载自blog.csdn.net/wang903039690/article/details/81206668
今日推荐