当前位置:网站首页>电赛必备技能___定时ADC+DMA+串口通信
电赛必备技能___定时ADC+DMA+串口通信
2022-08-05 00:06:00 【c语言的神】
一,TIM定时
ADC采样是stm32学习中的必备技能,但是初期学习ADC采样大多没有采样频率这中要求,都是只要采样到一个数据就显示出来或者发送到串口,这样有一些不足之处,就是当你需要采集一个固定的频率的信号是,需要对他进行处理,所以对这个信号进行采样的数量必须要是可控的,不可能说你这个周期采样了100点,下个周期采样了120个点,这样无疑增加数据处理的难度。所以我们需要有一个信号来触发ADC的采样,且这个信号是有着固定频率,而且是可调的。这个时候我们应该想到用定时器的外部触发去实现这个功能。
可以使用定时器去产生一个脉冲信号去触发ADC,通道调整脉冲的频率去控制ADC的采样时间。脉冲信号的占空比,我设置为50%,没有试过其他占空比。
二,ADC+DMA+串口
ADC+DMA这部分的思路是,先用一个大的数组把所有通道采集的信号收集起来,然后按照各个通道在规则组的顺序,依次取出,比如说我有4个通道,规则组顺序为1,2,3,4。那么我在DMA数组ADC_ConvertedValue里面通道1就是数组里面的k,k+1,k+2,k+3(k=0)。再放到相应的数组里面,分别进行处理。这里有一个细节就是我申请的是DMA的中断,这样当DMA的传输计数器为0是触发中断,我这里把ADC_ConvertedValue的数组的大小与传输计数器一样,这样我当我把数据收集齐的时候,进入中断里面把所有的数取出来。串口部分过于简单不再赘述。
三,代码部分
#include "adc.h"
#include "delay.h"
#include "usart.h"
#define ADC1_DR_Address ((u32)0x4001244C) //ADC1的地址
uint16_t ADC_ConvertedValue[4096];
uint16_t sys_out1[1024];
uint16_t sys_out2[1024];
uint16_t sys_out3[1024];
uint16_t sys_out4[1024];
uint8_t flag_adc;
int cnt=0;
int k=0;
void TIM2_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=arr;
TIM_TimeBaseInitStructure.TIM_Prescaler=psc;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_Pulse=20;//CCR
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC2Init(TIM2, & TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE); //使能TIMx
TIM_CtrlPWMOutputs(TIM2, ENABLE);
}
void DMA1_Init()
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
//DMA1初始化
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //ADC1地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue; //内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //方向(从外设到内存)
DMA_InitStructure.DMA_BufferSize = 4096; //传输内容的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址固定
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增,
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; //外设数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ; //内存数据单位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ; //DMA模式:循环传输
DMA_InitStructure.DMA_Priority = DMA_Priority_High ; //优先级:高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止内存到内存的传输
DMA_Init(DMA1_Channel1, &DMA_InitStructure); //配置DMA1
DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE); //使能传输完成中断
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_Cmd(DMA1_Channel1,ENABLE);
}
void Adc_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE); //使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1通道时钟
//PA6 PA7 PC4 PC5作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
DMA1_Init();
TIM2_Init(39,17);//100k的采样率
//ADC1初始化
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立ADC模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //关闭扫描方式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //关闭连续转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //使用外部触发模式
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //采集数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 4; //要转换的通道数目
ADC_Init(ADC1, &ADC_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //配置ADC时钟,为PCLK2的6分频,即12Hz
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 2, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 3, ADC_SampleTime_1Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 4, ADC_SampleTime_1Cycles5);
//使能ADC、DMA
ADC_DMACmd(ADC1,ENABLE);
ADC_Cmd(ADC1,ENABLE);
ADC_ResetCalibration(ADC1); //复位校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1)); //等待校准寄存器复位完成
ADC_StartCalibration(ADC1); //ADC校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准完成
ADC_ExternalTrigConvCmd(ADC1, ENABLE); //设置外部触发模式使能
}
void DMA1_Channel1_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_IT_TC1)!=RESET){
for(k=0;k<4096;k+=4){
sys_out1[cnt]=ADC_ConvertedValue[k];
sys_out2[cnt]=ADC_ConvertedValue[k+1];
sys_out3[cnt]=ADC_ConvertedValue[k+2];
sys_out4[cnt]=ADC_ConvertedValue[k+3];
cnt++;
if(cnt==1024)
{
flag_adc=1;
ADC_Cmd(ADC1,DISABLE);
DMA_Cmd(DMA1_Channel1,DISABLE);
cnt=0;
}
}
}
DMA_ClearITPendingBit(DMA1_IT_TC1);
}
flag_adc是用来确定你的采样周期的,可以选择一直循环,也可以执行相应次数。有疑问可以在下面留言。
边栏推荐
猜你喜欢
手写分布式配置中心(1)
what?测试/开发程序员要被淘汰了?年龄40被砍到了32?一瞬间,有点缓不过神来......
leetcode经典例题——单词拆分
uniapp sharing function - share to friends group chat circle of friends effect (sorting)
性能测试如何准备测试数据
找不到DiscoveryClient类型的Bean
Statistical words (DAY 101) Huazhong University of Science and Technology postgraduate examination questions
KT148A语音芯片ic工作原理以及芯片的内部架构描述
SQL association table update
Nuclei (2) Advanced - In-depth understanding of workflows, Matchers and Extractors
随机推荐
Chinese and Japanese color style
Cython
Essential knowledge for entry-level 3D game modelers
情人节---快来学习一下程序员的专属浪漫吧
KT148A语音芯片怎么烧录语音进入芯片里面通过串口和电脑端的工具
Develop a SpaceX website based on the Appian low-code platform
~ hand AHB - APB Bridge 】 【 AMBA AHB bus
工业物联网 —— 新型数据库的召唤
uniapp横向选项卡(水平滚动导航栏)效果demo(整理)
Nuclei(二)进阶——深入理解workflows、Matchers和Extractors
关于使用read table 语句
3. Actual combat---crawl the result page corresponding to Baidu's specified entry (a simple page collector)
导入JankStats检测卡帧库遇到问题记录
2022年华数杯数学建模
Cloud native - Kubernetes 】 【 scheduling constraints
uniapp horizontal tab (horizontal scrolling navigation bar) effect demo (organization)
Implementation principle of golang coroutine
Ab3d.PowerToys and Ab3d.DXEngine Crack
2022牛客暑期多校训练营5(BCDFGHK)
Flask框架 根据源码分析可扩展点