STM32基础设计(6)---ADC转换(DMA方式)

本文简单介绍了STM32F103C8,通过DMA方式读取ADC并通过串口中断向电脑端打印出当前电源ADC的值。

现在先将设计过程的主要步骤介绍如下:

                1,串口配置

                2,中断配置

                3,DMA配置

                4,ADC配置

                5,中断服务函数

                6,主函数

       先总结下博主在这次基础设计中犯的错误,在中断初始化函数中,没有将中断通道使能,导致电脑端没有接收到数据,发现后就去检查串口初始化函数了,结果没有发现错误,而是检查了一遍代码才发现错误。发现串口无法工作后,先核查初始化函数,如果问题没有解决,第二步,如果是串口中断方式,接下来检查,中断初始化函数,如果是串口查询方式,接下来检查主函数的串口查询代码。

接下来详细介绍各个步骤:

1,串口配置

void usart_init(void)
{
	GPIO_InitTypeDef GPIO_usart;定义GPIO结构体
	USART_InitTypeDef USART_usart;定义串口结构体
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1 ,ENABLE);使能外设时钟
	
	GPIO_usart.GPIO_Pin = GPIO_Pin_9;
	GPIO_usart.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_usart.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_usart);配置发送口
	
	GPIO_usart.GPIO_Pin = GPIO_Pin_10;
	GPIO_usart.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_usart.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_usart);配置接受口
	
	USART_usart.USART_BaudRate = 115200;设置传输波特率
	USART_usart.USART_WordLength = USART_WordLength_8b;设置串口发送字长
	USART_usart.USART_StopBits = USART_StopBits_1;设置停止位
	USART_usart.USART_Parity = USART_Parity_No;不进行奇偶校验
	USART_usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;硬件流使能
	USART_usart.USART_Mode = USART_Mode_Tx;设置为发送模式
	USART_Init(USART1,&USART_usart);初始化串口寄存器
	
	USART_Cmd(USART1,ENABLE);串口使能
	USART_ClearFlag(USART1,USART_FLAG_TC);清除已发送位,防止第一位发不出去
}

2,中断配置

void nvic_init(void)
{
	NVIC_InitTypeDef nvic_usart;定义中断结构体
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);设置中断分组
	nvic_usart.NVIC_IRQChannel = USART1_IRQn;制定中断服务函数通道
	nvic_usart.NVIC_IRQChannelPreemptionPriority = 1;抢占优先级1
	nvic_usart.NVIC_IRQChannelSubPriority = 0;子优先级0
	nvic_usart.NVIC_IRQChannelCmd = ENABLE;通道使能
	NVIC_Init(&nvic_usart);中断寄存器初始化
}

3,DMA配置

void dma_init(void)
{
	DMA_InitTypeDef dma;定义DMA结构体
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);打开时钟
	
	DMA_DeInit(DMA1_Channel1);现将DMA,通道1寄存器复位
	dma.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;设置外设地址
	dma.DMA_MemoryBaseAddr = (uint32_t)ADC_Value;设置存储器地址
	dma.DMA_DIR = DMA_DIR_PeripheralSRC;设置传输方向为 外设到存储器
	dma.DMA_BufferSize = 2;数据缓冲为设置为2
	dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;外设地址固定
	dma.DMA_MemoryInc = DMA_MemoryInc_Enable;寄存器地址自增
	dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;外设数据位宽度半字
	dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;存储器数据位宽度半字
	dma.DMA_Mode = DMA_Mode_Circular;DMA工作在循环模式
	dma.DMA_Priority = DMA_Priority_High;DMA通道为高优先级
	dma.DMA_M2M = DMA_M2M_Disable;内存到内存传输使能
	DMA_Init(DMA1_Channel1,&dma);初始化DMA寄存器
	
	//DMA_Cmd(DMA1_Channel1,ENABLE);使能通道1 (笔者把这句放到主函数中了,在这里写也行,只不过是笔者认为放到主函数中便于理解)
}

4,adc配置

void adc_init(void)
{
	ADC_InitTypeDef adc;定义adc结构体
	GPIO_InitTypeDef adc_gpio;定义GPIO结构体
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB,ENABLE);使能外设
	
	adc_gpio.GPIO_Pin = GPIO_Pin_1;
	adc_gpio.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOB,&adc_gpio);使能ADC的测试通道
	
	ADC_DeInit(ADC1);复位ADC1寄存器
	ADC_TempSensorVrefintCmd(ENABLE);使能内部参照电压
	adc.ADC_Mode = ADC_Mode_Independent;ADC工作在独立模式
	adc.ADC_ScanConvMode = ENABLE;使用扫描模式
	adc.ADC_ContinuousConvMode = ENABLE;使用连续转换模式
	adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;不使用外部触发工作模式
	adc.ADC_DataAlign = ADC_DataAlign_Right;数据设置为右对齐
	adc.ADC_NbrOfChannel = 2;两个转换通道
	
	ADC_Init(ADC1,&adc);初始化寄存器
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_9,1,ADC_SampleTime_239Cycles5);对通道9采样(电源电压)
	ADC_RegularChannelConfig(ADC1,ADC_Channel_17,2,ADC_SampleTime_239Cycles5);对通道11采样(参考电压)
	
	//ADC_DMACmd(ADC1,ENABLE);ADC 的DMA通道使能
	
	//ADC_Cmd(ADC1,ENABLE);ADC使能
	
	//ADC_ResetCalibration(ADC1);复位ADC1的校准寄存器
	//while(ADC_GetResetCalibrationStatus(ADC1));等待复位完成
	
	//ADC_StartCalibration(ADC1);开始ADC1校准
	//while(ADC_GetCalibrationStatus(ADC1));等待校准完成
	
	//ADC_SoftwareStartConvCmd(ADC1,ENABLE);ADC1的软件转换使能(注:这些注释的部分我放到主函数里了,放在这里也行,只不过,我感觉我那样便于理解)
}

5,中断服务函数

void USART1_IRQHandler(void)
{
	if(USART1->SR & USART_SR_TC)判断是否能发送数据
	{
		USART1->DR = TxBuff[TxCount++];笔者将转换到的电压值存到TxBuff[0]中了
		if(TxCount == Count)等到传完一次数据,就退出中断
		{
			USART1->CR1 &= ~USART_CR1_TXEIE;
		}
	}
}

6,主函数

int main()
{
	usart_init();串口初始化
	nvic_init();中断初始化
	dma_init();DMA初始化
	adc_init();ADC初始化
	DMA_Cmd(DMA1_Channel1,ENABLE);//见上文
	ADC_DMACmd(ADC1,ENABLE);同上
	
	ADC_Cmd(ADC1,ENABLE);同上
	
	ADC_ResetCalibration(ADC1);同上
	while(ADC_GetResetCalibrationStatus(ADC1));同上
	
	ADC_StartCalibration(ADC1);同上
	while(ADC_GetCalibrationStatus(ADC1));同上
	
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);同上
	while(1)循环打印电压值
	{
		Voltage_Printf();用于打印电压
		//PrintString("\r\nprint data!!\r\n");
		delay(1000);延时
	}
void Voltage_Printf(void)
{
	Battery = (uint16_t)(2.0f *ADC_Value[0] / ADC_Value[1] *1.2f * 100);根据参考电压按比例计算电源电压
	PrintString("\r\n当前电压值的一百倍:");
	PrintU16(Battery);
	PrintString("V");
}
下面粘贴完整代码
#include<stm32f10x.h>

uint16_t ADC_Value[2];
static uint16_t Battery=0;
uint8_t TxCount = 0;
uint8_t Count = 0;
static uint8_t TxBuff[250];
volatile uint8_t RxBuffer[50];

void delay(uint32_t n)
{
	int i,j;
	for(i=0;i<n;i++)
		for(j=0;j<8500;j++);
}

void usart_init(void)
{
	GPIO_InitTypeDef GPIO_usart;
	USART_InitTypeDef USART_usart;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1 ,ENABLE);
	
	GPIO_usart.GPIO_Pin = GPIO_Pin_9;
	GPIO_usart.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_usart.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_usart);
	
	GPIO_usart.GPIO_Pin = GPIO_Pin_10;
	GPIO_usart.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_usart.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_usart);
	
	USART_usart.USART_BaudRate = 115200;
	USART_usart.USART_WordLength = USART_WordLength_8b;
	USART_usart.USART_StopBits = USART_StopBits_1;
	USART_usart.USART_Parity = USART_Parity_No;
	USART_usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_usart.USART_Mode = USART_Mode_Tx;
	USART_Init(USART1,&USART_usart);
	
	USART_Cmd(USART1,ENABLE);
	USART_ClearFlag(USART1,USART_FLAG_TC);
}
	
void nvic_init(void)
{
	NVIC_InitTypeDef nvic_usart;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	nvic_usart.NVIC_IRQChannel = USART1_IRQn;
	nvic_usart.NVIC_IRQChannelPreemptionPriority = 1;
	nvic_usart.NVIC_IRQChannelSubPriority = 0;
	nvic_usart.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvic_usart);
}
	
void dma_init(void)
{
	DMA_InitTypeDef dma;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	DMA_DeInit(DMA1_Channel1);
	dma.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;
	dma.DMA_MemoryBaseAddr = (uint32_t)ADC_Value;
	dma.DMA_DIR = DMA_DIR_PeripheralSRC;
	dma.DMA_BufferSize = 2;
	dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
	dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	dma.DMA_Mode = DMA_Mode_Circular;
	dma.DMA_Priority = DMA_Priority_High;
	dma.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel1,&dma);
	
	//DMA_Cmd(DMA1_Channel1,ENABLE);
}
void adc_init(void)
{
	ADC_InitTypeDef adc;
	GPIO_InitTypeDef adc_gpio;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB,ENABLE);
	
	adc_gpio.GPIO_Pin = GPIO_Pin_1;
	adc_gpio.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOB,&adc_gpio);
	
	ADC_DeInit(ADC1);
	ADC_TempSensorVrefintCmd(ENABLE);
	adc.ADC_Mode = ADC_Mode_Independent;
	adc.ADC_ScanConvMode = ENABLE;
	adc.ADC_ContinuousConvMode = ENABLE;
	adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	adc.ADC_DataAlign = ADC_DataAlign_Right;
	adc.ADC_NbrOfChannel = 2;
	
	ADC_Init(ADC1,&adc);
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_9,1,ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_17,2,ADC_SampleTime_239Cycles5);
	
	//ADC_DMACmd(ADC1,ENABLE);
	
	//ADC_Cmd(ADC1,ENABLE);
	
	//ADC_ResetCalibration(ADC1);
	//while(ADC_GetResetCalibrationStatus(ADC1));
	
	//ADC_StartCalibration(ADC1);
	//while(ADC_GetCalibrationStatus(ADC1));
	
	//ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}
void PrintHexU8(uint8_t data)
{
	TxBuff[Count++] = data;
	if(!(USART1->CR1 & USART_CR1_TXEIE))
		USART_ITConfig(USART1,USART_IT_TXE,ENABLE);
}

void PrintString(uint8_t *s)
{
	uint8_t *p;
	p=s;
	while(*p!= '\0')
	{
		PrintHexU8(*p);
		p++;
	}
}

void PrintU16(uint16_t num)
{
	uint8_t w5,w4,w3,w2,w1;
	 w5 = num % 100000/10000;  
   w4 = num % 10000/1000;  
   w3 = num % 1000/100;  
   w2 = num % 100/10;  
   w1 = num % 10;  
   PrintHexU8('0' + w5);  
   PrintHexU8('0' + w4);  
   PrintHexU8('0' + w3);  
   PrintHexU8('0' + w2);  
   PrintHexU8('0' + w1); 
}

void Voltage_Printf(void)
{
	Battery = (uint16_t)(2.0f *ADC_Value[0] / ADC_Value[1] *1.2f * 100);
	PrintString("\r\nµ±Ç°µç³Øµçѹֵһ°Ù±¶£º");
	PrintU16(Battery);
	PrintString("V");
}
int main()
{
	usart_init();
	nvic_init();
	dma_init();
	adc_init();
	DMA_Cmd(DMA1_Channel1,ENABLE);
	ADC_DMACmd(ADC1,ENABLE);
	
	ADC_Cmd(ADC1,ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));
	
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	while(1)
	{
		Voltage_Printf();
		//PrintString("\r\nprint data!!\r\n");
		delay(1000);
	}
}
	
void USART1_IRQHandler(void)
{
	if(USART1->SR & USART_SR_TC)
	{
		USART1->DR = TxBuff[TxCount++];
		if(TxCount == Count)
		{
			USART1->CR1 &= ~USART_CR1_TXEIE;
		}
	}
	
	if(USART1->SR & USART_SR_RXNE)
	{
		volatile int8_t com_data;
		com_data = USART1->DR;
	}
}





  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值