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