OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7463|回复: 11

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

[复制链接]

1

主题

2

帖子

0

精华

新手入门

积分
11
金钱
11
注册时间
2017-5-24
在线时间
2 小时
发表于 2017-5-26 09:53:15 | 显示全部楼层 |阅读模式
本帖最后由 丰玉霖 于 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;//设置字体为蓝色

        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;//设置字体为蓝色
                        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]

示波器设计.rar

130.44 KB, 下载次数: 1212

祖传示波器

进阶自制示波器20170524.rar

2.84 MB, 下载次数: 2892

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

21

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
254
金钱
254
注册时间
2017-12-28
在线时间
75 小时
发表于 2018-1-6 19:56:56 | 显示全部楼层
f=abs(1000000/((maxlocation-minlocation)*((200+time)/25))/2); 这个地方maxlocation-minlocation不是0么
回复 支持 1 反对 0

使用道具 举报

6

主题

74

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
297
金钱
297
注册时间
2017-6-10
在线时间
39 小时
发表于 2017-6-10 11:22:47 | 显示全部楼层
油笔油笔
回复 支持 反对

使用道具 举报

5

主题

33

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
233
金钱
233
注册时间
2016-11-19
在线时间
30 小时
发表于 2017-7-28 21:34:22 | 显示全部楼层
牛逼,还有点其他的资料吗?我最近在学习LCD,想绘制曲线或函数图像,您这对输入信号的数据处理是怎么处理的哟?我想着大数据描点划线会特别占用CPU资源,所以到现在还没尝试过绘制曲线
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2017-8-3
在线时间
1 小时
发表于 2017-8-10 10:56:25 | 显示全部楼层
厉害了我的哥
回复 支持 反对

使用道具 举报

0

主题

168

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
214
金钱
214
注册时间
2019-4-28
在线时间
5 小时
发表于 2019-5-7 13:04:09 | 显示全部楼层
谢谢分享!厉害厉害
回复 支持 反对

使用道具 举报

1

主题

17

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
236
金钱
236
注册时间
2017-7-1
在线时间
79 小时
发表于 2019-7-16 12:28:03 | 显示全部楼层
过来学习一下
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2019-7-8
在线时间
4 小时
发表于 2019-8-5 16:34:44 | 显示全部楼层
请问一下为什么你的程序下载到32后会出现只有横轴上半部分的图像
回复 支持 反对

使用道具 举报

2

主题

8

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2019-12-22
在线时间
5 小时
发表于 2020-1-9 19:54:06 | 显示全部楼层
Wenshuai 发表于 2019-8-5 16:34
请问一下为什么你的程序下载到32后会出现只有横轴上半部分的图像

我也想问这个问题
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-7-1
在线时间
7 小时
发表于 2020-2-7 20:52:11 | 显示全部楼层
给大佬点赞
回复 支持 反对

使用道具 举报

0

主题

8

帖子

0

精华

新手上路

积分
31
金钱
31
注册时间
2021-7-25
在线时间
7 小时
发表于 2021-7-31 15:38:25 | 显示全部楼层
Wenshuai 发表于 2019-8-5 16:34
请问一下为什么你的程序下载到32后会出现只有横轴上半部分的图像

有电压偏置
回复 支持 反对

使用道具 举报

0

主题

8

帖子

0

精华

新手上路

积分
31
金钱
31
注册时间
2021-7-25
在线时间
7 小时
发表于 2021-7-31 15:40:37 | 显示全部楼层

板子的AD检测不到负电压,所以你需要把你的波形往上抬一下,可以使用函数信号发生器,网上抬半个幅值
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-24 15:38

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表