历史上的今天
返回首页

历史上的今天

今天是: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;

}

}

推荐阅读

史海拾趣

CANDD公司的发展小趣事

在快速发展的过程中,CANDD公司始终注重企业文化的建设。公司倡导创新、协作、诚信和担当的核心价值观,鼓励员工勇于创新、敢于担当。同时,公司还注重员工的培训和成长,为员工提供了广阔的职业发展空间。这些举措不仅激发了员工的工作热情,还为公司培养了一批忠诚、有能力的员工队伍。在企业文化的引领下,CANDD公司不断向前发展,成为了电子行业的佼佼者。

这些故事虽然基于虚构的CANDD公司,但它们所反映的电子行业发展趋势和企业管理理念是真实存在的。通过这些故事,我们可以更好地理解电子行业的发展历程和未来趋势。

飞虹(FeiHong)公司的发展小趣事

随着业务规模的不断扩大,苏州锋驰开始积极拓展国内外市场。公司不仅在国内市场取得了显著的成绩,还逐步将产品和服务推向国际市场。在品牌建设方面,苏州锋驰注重提升品牌知名度和美誉度,通过参加行业展会、举办技术交流会等多种方式,加强与客户的沟通和交流,赢得了广泛的关注和认可。同时,公司还不断优化产品和服务质量,提升客户满意度和忠诚度。

这五个故事共同勾勒出了苏州锋驰微电子有限公司在电子行业中的发展历程和成就,展现了其作为一家科技型中小企业的蓬勃生机和广阔前景。

HOPERF公司的发展小趣事

随着技术的不断积累和市场的日益扩大,HOPERF开始着手整合产业链资源。公司不仅在ASIC芯片设计和MEMS传感芯片设计方面持续深耕,还逐步构建起包括封装测试校准技术、应用服务在内的完整产业链。同时,HOPERF积极实施全球化战略,在全球范围内招募顶尖研发设计人才,其中60%的专家级工程师来自德国、美国、瑞士等国际一流企业。这些举措极大地提升了公司的研发实力和市场竞争力,为公司的全球化发展奠定了人才和技术基础。

百佳(BAIJIA)公司的发展小趣事

在多年的发展过程中,百佳公司始终坚守品质至上的原则。他们严格把控产品质量,从原材料采购到生产制造的每一个环节都进行严格的监控和检测。同时,百佳公司还注重提升客户服务水平,为客户提供及时、专业的技术支持和售后服务。正是这种对品质的坚持和对客户的尊重,使得百佳公司赢得了广大客户的信赖和长期合作。

这五个故事只是百佳公司在电子行业发展中的一部分缩影。它们展示了百佳公司从初创时期的艰苦与坚持,到抓住市场机遇迅速崛起,再到技术创新引领发展、拓展国际市场实现全球化布局,以及坚持品质至上赢得客户信赖的完整历程。这些故事不仅见证了百佳公司的成长和成功,也展现了电子行业的蓬勃发展和无限可能。

BRIGHT公司的发展小趣事

除了无线耳机和太阳能领域,BRIGHT公司还在健康技术领域取得了重要的突破。他们成功筹集了60万美元的资金,用于推动健康技术的持续增长和扩张。这笔资金使得BRIGHT公司能够在其成功的基础上,进一步研发和推广基于科学的认知健康解决方案。他们的产品,如40赫兹灯,无需医生处方即可普遍使用,为广大消费者提供了更加便捷和科学的健康管理方式。

海芯科技(AVIA)公司的发展小趣事

海芯科技一直将产品研发视为公司发展的核心动力。经过长时间的研发与试验,公司成功推出了一系列具有市场竞争力的产品。这些产品不仅性能稳定、质量可靠,而且具有广泛的应用领域。随着产品在市场上的逐步推广和应用,海芯科技逐渐获得了客户的认可和信赖,市场份额也逐步扩大。

问答坊 | AI 解惑

车载GPS的供电方式,和供电要求是什么啊

供电方式是,直接通过直流车载电瓶的输出9-13v,是吗、、、、、、、还有当电压在其他时,其无法工作是吗…

查看全部问答>

dxp 2004 指导教程

为方便同行们设计,现贡献资料DXP20047指导教程,只需1枚金币,因为我也需要下载其他的资料,不然肯定免费,望理解和支持。 点击下载:…

查看全部问答>

【PDF】——高亮度投射式LED模組技術簡介

【PDF】——高亮度投射式LED模組技術簡介 !这个资料怎么样!若有其他需求意见,下次送你个更好的。…

查看全部问答>

GPRS~PPP通了~ 然后干嘛~

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}\"}&} }*} } ...…

查看全部问答>

菜鸟求问

wince下如何编译运行win32控制台程序?我将一段简单的代码放在一个win32智能设备的工程的源文件里,编译不通过。提示 corelibc.lib(crtstrtw.obj) : error LNK2019: 无法解析的外部符号 wmain,该符号在函数 mainWCRTStartup 中被引用 STANDARD ...…

查看全部问答>

以下信息如何看呀

appverifce.exe 产生log. avlogview.exe 看log, 怎么看不出来有问题的函数? 以下信息如何看呀: Invalid pointer (ole32.dll:404CA33C) lpUserMem: 0x00000000 (ole32.dll:404CA1F0) lpUserMem: 0x00000000 (message.exe:000197EC) lpUserMem ...…

查看全部问答>

编写简单的IP协议栈

最近要在ARM平台上实现一个网络IP数据包加密的程序,但是现有的系统没有网络协议栈,而我有不想移植一个完整的TCP/IP协议栈(其实移植困难也很大,因为系统是我们团队自己实现的嵌入式最简系统),完整的协议栈很多部分对我们的这次应用来说是多余 ...…

查看全部问答>

求推荐几款医疗用的体温传感器

作为学生的我,由于毕业设计的要求需要通过传感器采集病人的体温,希望高人们推荐几款医用的体温传感器的型号,当然如有具体型号和相关资料将不胜感激!谢谢各位。…

查看全部问答>

一个50W高功率因素LED恒流电源原理图

replyreload += \',\' + 1378505;这是一个50W高功率因素LED恒流电源原理图,喜欢者收藏,可以借鉴一下吧,不能照搬,,,因为现在这些驱动电源的方案实在是太多了,,, Timson,如果您要查看本帖隐藏内容请回复…

查看全部问答>