当前位置:网站首页>电赛必备技能___定时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是用来确定你的采样周期的,可以选择一直循环,也可以执行相应次数。有疑问可以在下面留言。
边栏推荐
- 大师教你3D实时角色制作流程,游戏建模流程分享
- MongoDB permission verification is turned on and mongoose database configuration
- d枚举生成位
- 【无标题】
- 美团二面:Redis与MySQL双写一致性如何保证?
- The role of @Async annotation and how to implement asynchronous listening mechanism
- what is MVCC
- 招标公告 | 海纳百创公众号运维项目
- Three tips for you to successfully get started with 3D modeling
- The role of the annotation @ EnableAutoConfiguration and how to use
猜你喜欢
美团二面:Redis与MySQL双写一致性如何保证?
【七夕快乐篇】Nacos是如何实现服务注册功能的?
Three tips for you to successfully get started with 3D modeling
MongoDB权限验证开启与mongoose数据库配置
三、实战---爬取百度指定词条所对应的结果页面(一个简单的页面采集器)
What is next-generation modeling (with learning materials)
Bidding Announcement | Operation and Maintenance Project of Haina Baichuang Official Account
[Cloud Native--Kubernetes] Pod Controller
线程三连鞭之“线程的状态”
Ab3d.PowerToys and Ab3d.DXEngine Crack
随机推荐
怎样进行在不改变主线程执行的时候,进行日志的记录
【无标题】线程三连鞭之“线程池”
【云原生--Kubernetes】Pod控制器
资深游戏建模师告知新手,游戏场景建模师必备软件有哪些?
【七夕快乐篇】Nacos是如何实现服务注册功能的?
MongoDB权限验证开启与mongoose数据库配置
2022年华数杯数学建模
Detailed explanation of common DNS resource record types
没有这些「伪需求」,产品经理的 KPI 怎么完成?
uniapp 分享功能-分享给朋友群聊朋友圈效果(整理)
数据类型-整型(C语言)
测试经理要不要做测试执行?
jenkins发送邮件系统配置
4-《PyTorch深度学习实践》-反向传播
what is MVCC
【LeetCode】滑动窗口题解汇总
Bidding Announcement | Operation and Maintenance Project of Haina Baichuang Official Account
Metasploit-域名上线隐藏IP
Couple Holding Hands [Greedy & Abstract]
【云原生--Kubernetes】调度约束