基于mini板、9341lcd、单通道adc 简易示波器

2019-07-20 22:31发布

本帖最后由 丰玉霖 于 2017-5-26 14:26 编辑
      这两天老师要求做电赛写单片机的boys开始写一个建议示波器,思路是学校代代祖传的,不过他们都用msp430系列写的,就我用stm32独立完成。写了两天,有一些疑惑,参考了论坛里许多代码,先实现了一个很基础很垃圾的应付检查,写在这里是为了整理自己的凌乱思路,不是什么特别friendly的分享帖,然后有一些问题想问,两个低端的,一个有点难的。
热烈欢迎原子哥以及其他大佬莅临指导!!!@正点原子
代码思路:         
通过单通道单次转换得到500个连续的ADC值,通过数据处理,(即与上次显示的值作比对,找到从哪里开始显示波形防止图片不稳)选出200个连续值打在屏幕上连线形成波形。图形的高度可调,采样率可以通过按键调整,对于较高的频率,可以调整往屏幕上打印的规则,即用将屏幕横向拉长,最高能测到20KHz。屏幕下方显示横格对应的时间,纵格对应电压,VPP,以及其他控制量。不足及优化:   
      1.除了按键是用外部中断,其他的一切都是在主函数完成的,包括adc采集,数据处理,液晶显示。下一步可能会学一学dma,如果有时间就优化一下。
      2.没有用到触发电平的方法整理波形,而是用根据上一次的初始电压,通过相位比较方法防止波形移动的,所以对方波,pwm信号的显示效果非常差。。。为什么不设置触发电平呢?按键少,嫌麻烦(可给我牛逼坏了,插会儿腰)。。。然而这是一定要加的,不加就不是完整的示波器了!
      3.采样率达不到理论最大值(约1M)。
      4.刷新频率太低,眼睛会看到屏幕闪烁。

问题:
                      1.我通过公式里的(1.5+12.5)*adc周期计算的采样频率是14/12us 即1.17us,但实际测量得到的结果是4.5us,是哪些地方拖慢了采样率呢?串口液晶屏?数据处理?
                      2.我刷新屏幕的频率大约是每秒两次,用的是LCD_Clear(BLACK); 一闪一闪的,有没有优雅一点的方法?
                      3.我现在的采样率是1/4.5us=222KHz,根据采样定律,我可以采集100KHz以内的波形,该怎么做呢?能不能给个思路呢?



      先贴几张图





      算了网不太好贴不上来。。。


下面是adc初始化代码
[mw_shl_code=cpp,true]void  Adc_Init(void)
{         
        ADC_InitTypeDef ADC_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1        , ENABLE );          //使能ADC1通道时钟


        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

        //PA1 作为模拟通道输入引脚                        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
        GPIO_Init(GPIOA, &GPIO_InitStructure);        

        ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
        ADC_InitStructure.ADC_ScanConvMode = DISABLE;        //模数转换工作在单通道模式
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
        ADC_InitStructure.ADC_NbrOfChannel = 1;        //顺序进行规则转换的ADC通道的数目
        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

  
        ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1
        
        ADC_ResetCalibration(ADC1);        //使能复位校准  
         
        while(ADC_GetResetCalibrationStatus(ADC1));        //等待复位校准结束
        
        ADC_StartCalibration(ADC1);         //开启AD校准

        while(ADC_GetCalibrationStatus(ADC1));         //等待校准结束

//        ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能

}                                  [/mw_shl_code]



下面是庞大的main.c
[mw_shl_code=cpp,true]#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "adc.h"
#include "exti.h"

//ALIENTEK Mini STM32开发板范例代码15
//ADC实验  
//技术支持:www.openedv.com
//广州市星翼电子科技有限公司

int time=0;              //为了降低采样率而加延时
u8 sharp=1;              //为了将横向拉长
float high=1;               //为了纵向缩放
u16 buf[10]={0};         //用作缓冲数据
u16 adc[500];            //装载要绘制的波形
float frequency=0;
u8 mode=0;

void drawgaid() //画网格
{
        u16 x,y;
        for(x=0;x<201;x=x+25)
                for(y=0;y<251;y=y+5)
                {
                        LCD_Fast_DrawPoint(x,y,YELLOW );
                }
        for(y=0;y<251;y=y+25)
                for(x=0;x<201;x=x+5)
                {
                        LCD_Fast_DrawPoint(x,y,YELLOW );
                }
}


float get_Vppandfrequency()     //看数组,找max,min,时间差,算VPP,周期
{
        int adcmax=0;
        int adcmin=0;
        float f=0;
        int i=0,maxlocation=0,minlocation=0;
        float VPP;
        for(i=0,adcmax=adc[0],adcmin=adc[0];i<500;i++)
        {
                if(adc>adcmax+10) adcmax=adc;
                if(adc<adcmin-10) adcmin=adc;
        }
        VPP=(adcmax-adcmin)*(3.3/4096);
        f=abs(1000000/((maxlocation-minlocation)*((200+time)/25))/2);
        if(f!=0) frequency=f;
        return VPP;
}
        

int findbegin()              //通过比较与上一的波形比较,找到该从1何处开始画
{
        int i,a;
        for(i=0,a=0;i<250&&a<10;)
        {
                if(adc[i+a]>buf[a]-50&&adc[i+a]<buf[a]+50) a++;//符合:向下比较
                else i++,a=0;                                    //不符合:i++,a置零,重比
        }
        return i;
}

void drawwave(int begin)             //从begin开始画200/sharp个点,到[0;sharp;200]
{
        int i=0;
        u16 x=0,y=0,temp=0,x0=0,y0=0;
        POINT_COLOR=BLUE;//设置字体为蓝 {MOD}

        for(i=begin;i<begin+200/sharp;i++)
        {
                x=(i-begin)*sharp;
                y=(u16)(125-(125*adc/4096)/high);
                LCD_Fast_DrawPoint(x,y,BLUE );
                if(i!=begin) LCD_DrawLine(x0,y0,x,y);
                x0=x,y0=y;
        }
}



int main(void)
{
                int i=0,a=0;
                int begin=0;             //找该从哪里描点
                float VPP;
                char length[50];
                NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
                delay_init();                     //延时函数初始化
                uart_init(9600);                 //串口初始化为9600
                EXTIX_Init();
                LED_Init();                                  //初始化与LED连接的硬件接口
                LCD_Init();
                Adc_Init();                                  //ADC初始化
                LCD_Clear(BLACK);
                drawgaid();
               
        
        
        while(1)
        {
               
                adc[i++]=Get_Adc(ADC_Channel_1);                 //填入数组
                if(time>0) delay_us(time);
               
                if(i==500)
                {
                        begin=findbegin();
                        LCD_Clear(BLACK);
                        drawgaid();
                        drawwave(begin);
                        
                        VPP=get_Vppandfrequency(begin);
                        POINT_COLOR=BLUE;//设置字体为蓝 {MOD}
                        sprintf((char*)length,"VPP=%4.4lfV",VPP);          //为了VCC数值输出
                        LCD_ShowString(0,260,200,12,12,length);
                        sprintf((char*)length,"frequency=%4.4lfHZ",frequency);
                        LCD_ShowString(100,260,200,12,12,length);
                        sprintf((char*)length,"time=%4d",time);
                        LCD_ShowString(0,280,200,12,12,length);
                        sprintf((char*)length,"sharp=%4d",sharp);
                        LCD_ShowString(100,280,200,12,12,length);
                        sprintf((char*)length,"mode=%d",mode);
                        LCD_ShowString(0,300,200,12,12,length);
                        sprintf((char*)length,"timeperiod=%4.4lfus",(4.5+(float)time)*25/sharp);//通过实验强行推出采样率,得到每格的时间
                        LCD_ShowString(0,240,200,12,12,length);
                        sprintf((char*)length,"Vperiod=%4.4lfV",3.3/5/high);//每纵格代表的电压
                        LCD_ShowString(0,220,200,12,12,length);
                        for(a=0;a<10;a++)
                        {
                                buf[a]=adc[begin+a];           //将本次输入点存档
                        }
                        i=0;
                        LED0=!LED0;
                        delay_ms(250);
                }
        }                                                                                    
}
[/mw_shl_code]

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。