本文简单介绍了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;
}
}