历史上的今天
今天是:2025年01月29日(星期三)
2019年01月29日 | STM32基础设计(6)---ADC转换(DMA方式)
2019-01-29 来源:eefocus
本文简单介绍了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
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 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; } }
史海拾趣
|
AT OK AT+CGATT=1 OK AT+CGDCONT=1,IP,CMNET OK AT+CGACT=1,1 OK AT+CGPADDR=1 +CGPADDR: 1,\"10.115.239.172\" OK AT+CGDATA=PPP,1 CONNECT ~?}#!}!}#} }9}\"}&} }*} } }\'}\"}(}\"}%}&mA?}#}%?}%e﹡ ~?}#?}!}#} }9}\"}&} }*} } ...… 查看全部问答> |
|
最近要在ARM平台上实现一个网络IP数据包加密的程序,但是现有的系统没有网络协议栈,而我有不想移植一个完整的TCP/IP协议栈(其实移植困难也很大,因为系统是我们团队自己实现的嵌入式最简系统),完整的协议栈很多部分对我们的这次应用来说是多余 ...… 查看全部问答> |
|
作为学生的我,由于毕业设计的要求需要通过传感器采集病人的体温,希望高人们推荐几款医用的体温传感器的型号,当然如有具体型号和相关资料将不胜感激!谢谢各位。… 查看全部问答> |
|
replyreload += \',\' + 1378505;这是一个50W高功率因素LED恒流电源原理图,喜欢者收藏,可以借鉴一下吧,不能照搬,,,因为现在这些驱动电源的方案实在是太多了,,, Timson,如果您要查看本帖隐藏内容请回复… 查看全部问答> |




