简易波形系统(简易示波器部分)
具体知识内容:
1.整体框图
2.示波器重要驱动和软件设计
整体框图
一、示波器重要驱动和软件设计
<1>重要驱动设计(PWM)
1.ADC+DMA+TIM的综合应用
ADC的采样频率由TIM定时器控制,采样周期=ADC自身的采样时间+TIM定时器的更新时间,ADC的自身采样时间在STM32标准库中设置ADC_RegularChannelConfig()函数来控制采样周期.
在72MHZ的主频下,ADC自身的采样频率:
计算公式:TCONV = 采样时间+ 12.5个周期
例如:
当ADCCLK=14MHz,采样时间为1.5周期
TCONV = 1.5 + 12.5 = 14周期 = 1μs
显然这并不满足采样各种频率,如果频率小于1KHZ一下,即使设置最大的采样频率也会造成后面在液晶屏上做出波形的麻烦,所以我们使用TIM定时器来控制ADC的采样频率,使ADC的整体采样频率调节灵活性得到最大提升。
ADC外部触发概览(使用的芯片为C8T6)
这里选择TIM3_TRGO事件为ADC采样的触发源,TRGO信号发生设置为定时器更新触发
---------------------------------------------------------------------------------------部分代码:
定时器初始化代码:
void Tim3_Timer_Config(uint16_t Period,uint16_t Prescaler,FunctionalState NewState)
{
TIM_TimeBaseInitTypeDef TIM3_Init_Structure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM3_Init_Structure.TIM_Period=Period;
TIM3_Init_Structure.TIM_Prescaler=Prescaler;
TIM3_Init_Structure.TIM_CounterMode=TIM_CounterMode_Up;
TIM3_Init_Structure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIMx,&TIM3_Init_Structure);
// Tim3_Nvic_Config();
// TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
TIM_SelectOutputTrigger(TIMx,TIM_TRGOSource_Update);
TIM_SelectMasterSlaveMode(TIMx,TIM_MasterSlaveMode_Enable);
TIM_Cmd(TIMx,NewState);
}
ADC初始化代码:
Adc_Init_Structure.ADC_Mode=ADC_Mode_Independent;//独立
Adc_Init_Structure.ADC_ContinuousConvMode=DISABLE;//不使用ADC连续触发,不然第一次触发以后会连续触发!
Adc_Init_Structure.ADC_DataAlign=ADC_DataAlign_Right;//右
Adc_Init_Structure.ADC_ScanConvMode=DISABLE;//单通道
Adc_Init_Structure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T3_TRGO;//用外部
Adc_Init_Structure.ADC_NbrOfChannel=ADC_Channel_1;//通道数量
ADC_Cmd(ADC1,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div2);//ADC时钟设置
//最大28us 最小0.5us
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_1Cycles5);//选择通道,通道优先级,采样时间 12MHZ,26个周期,26/12=2.1us采样一次
ADC_ExternalTrigConvCmd(ADC1,ENABLE);//使用外部触发转换
// ADC开始校准
ADC_StartCalibration(ADC1);
// 等待校准完成
while(ADC_GetCalibrationStatus(ADC1));
ADC代码注意点:
使用TIMx触发以后无需使能ADC连续采样和开启ADC触发函数!
示波器ADC采样存储思路:将ADC采样数据依次存储在长度为LEN的数组中,存储完成后主循环检测标志位进行处理。
问题:如何使存储更方便和高效呢?
答:可使用DMA搬运ADC采样数据到指定的内存中,开启DMA中断,DMA处理完后触发中断,设置相应的标志位进行处理。
DMA配置代码:
Dma_Init_Structure.DMA_PeripheralBaseAddr=(uint32_t)(&(ADC1->DR));//外设地址是ADC1_DR寄存器地址;
Dma_Init_Structure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//双字节
Dma_Init_Structure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//ADC不自增
Dma_Init_Structure.DMA_MemoryBaseAddr=(uint32_t)(&Adc_Arr[0]);
Dma_Init_Structure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//双字节
Dma_Init_Structure.DMA_MemoryInc=DMA_MemoryInc_Enable;//目标地址自增
Dma_Init_Structure.DMA_BufferSize=DATA_LEN;
Dma_Init_Structure.DMA_Mode=DMA_Mode_Circular;//循环存储
Dma_Init_Structure.DMA_DIR=DMA_DIR_PeripheralSRC;//方向 从外设到内存
Dma_Init_Structure.DMA_M2M=DMA_M2M_Disable;
Dma_Init_Structure.DMA_Priority=DMA_Priority_High;
DMA_Init(DMA1_Channel1,&Dma_Init_Structure);
DMA_Cmd(DMA1_Channel1,ENABLE);
Dma_Nvic_Config();
DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);//开启DMA中断
ADC_DMACmd(ADC1,ENABLE);
2.通过PWM捕获+ADC数据实现10-300KZ的波形捕获
思路:要实现捕获一定范围内的频率,还需要提前知道波形的频率,通过波形的频率来设置ADC采样频率,达到获取合理的数据,这个过程可看作Auto功能。
1.配置PWM捕获
2.在捕获中断中设置ADC采样频率
注意:输入的芯片引脚需要既有ADC通道,还有TIMx CH1/CH2功能,捕获和采样不能同时进行,这里使先捕获后采样,反复循环。具体根据所选的芯片选择引脚,如C8T6的PA0
部分代码(处理频率部分,根据自身情况配置定时器采样频率):
u8 Cap_Cnt=0;
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_CC1)!=RESET)
{
Wave_Mag.Cycle=TIM2->CCR1;
Wave_Mag.Pulse_W=TIM2->CCR2;
Cap_Cnt++;
Wave_Mag.Frequency=(float)(72000000.0/72.0/TIM2->CCR1);
// printf("%d\n",Wave_Mag.Pulse_W);
if(Wave_Mag.Frequency>=1000)
{
if((Wave_Mag.Frequency/1000>20))//高频信号
{
TIM3->ARR=5;
TIM3->PSC=Con_Shape.Hight_Psc;
}
else if((Wave_Mag.Frequency/1000>=15)&&(Wave_Mag.Frequency/1000<=20))
{
TIM3->ARR=20;
TIM3->PSC=Con_Shape.Hight_Psc;
}//高频信号
else//中频信号
{
TIM3->ARR=(uint32_t)(Con_Shape.Wave_Expand/(Wave_Mag.Frequency/1000.0));
TIM3->PSC=71;
}
}
else//低频信号
{
TIM3->ARR=(uint32_t)(Con_Shape.Wave_Expand*(1000.0/Wave_Mag.Frequency));
TIM3->PSC=71;
}
if(Cap_Cnt>5)//多次捕获频率为了获取到稳定的数据
{
Cap_Cnt=0;
Cap_Flag=1;
Scope_Shut_Cap(0);//关闭捕获开启ADC采样
}
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
3.在TFT液晶上显示波形
TFT选择2.2寸的ST7789,编写基本的显示驱动函数:画点/线,显示中文字符/英文字符,显示图片。
波形显示思路:
在获取的ADC数据中截取一段显示(增加显示的稳定性)
缺陷和问题:占空比无法显示,液晶刷新问题,格子无意义
总结
示波器部分还有很多欠缺,需要不断的修改和完善,代码波形处理写的比较烂,后续有更好的想法了再优化。