单片机课程设计:基于波形发生器的实现方案

怎么说呢,前面半个月被这个单片机课程设计搞得焦头烂额的,再加上运气属实有点“好”,就脾气有点“暴躁”,好的,也就骂了半天的脏话。有一说一,没有素质确实舒服。

好了,事情目前是过去了,那就好好回顾一下遇到的问题,以及找到了怎样的解决方案,和最后仍没有解决的问题。

电路设计方案

STC15F2K60S2

关于这个课程设计我遇到最大的问题就是电路设计方案的问题。在选择这个课题之前,我特意在B站上看了几个视频,嘛,眨眼一看,好像不难啊,还挺简单的。但事实就是我的第一印象过于浅薄了,有些东西往往看起来很简单,但等你自己动手的时候感觉就大有不同了。当然,也可能是笔者的水平过于低下了。

那么,插入我当时所观视频的仿真图片看看吧

它这里的电路元件不多,一个LCD1602显示模块,一个STC15F2K60S2单片机,两个编码器,以及一些电容电阻构成的滤波电路,还有用来调整显示屏对比度的滑动变阻器和校准波形的滑阻。

这个电路方案的作者是B站“爱捣鼓的老刘”,视频地址就放这儿了如何用单片机自制波形发生器生成方波和正弦波_哔哩哔哩_bilibili

选完这个课题隔了很久我去看了他的软件实现方案。实话就是:我TM看不懂!!!

倒不是说他那一行一行的代码我看不懂,每一行代码,它的语法含义都看得懂。但核心的地方在哪儿呢?在于他输出波形的地方我看不懂。好耶!他是用STC15系列的增强型PWM输出波形的。PWM(脉冲宽度调制),学过高频电子线路的应该知道,很多信号因为各种原因,并不能直接输出,就像我们移动通信的电磁波,它需要一个较高的频率才能在大气层(咱也不知道具体是哪儿,但肯定是天空中)中传输。但这些信号的原始频率并不一定有多高,所以,信号需要调制。像收音机的,它不是可以选择AM什么的吗?这个AM是幅度调制,除此之外还有频率调制,相位调制等等。而PWM是脉冲宽度调制的英文缩写。这个脉冲宽度调制呢,可以这么说:这会儿输出一个方波信号,也就是整个信号放在计算机中只代表着两个数,0和1.输出的只有一个高电平和低电平。随后就要提出一个新的概念,占空比。这个占空比指的是高电平在一个周期信号中所占的比例。而PWM,脉冲宽度调制,就是通过改变占空比来调制信号的。因为我对他这个电路方案和这个代码的输出波形部分不是那么了解,或者说得通俗易懂点,以我的知识储备,我看不懂他画的什么玩意儿,写的什么玩意儿,所以我放弃了这个电路设计方案。毕竟他只说输出正弦波与方波,我课程设计里的要求还有三角波、锯齿波、梯形波。

所以我最后采用的是另一种电路设计方案。

STC89C52RC

嗯,最后我用的就是那个全网最常见的电路设计方案。包括我没发这篇博客之前,你们在哪儿都能看到的电路设计方案。用STC89C52RC作为主控芯片,就51单片机的设计方案。除此之外,我整个电路里还用到的别的IC分别是DAC0832、LM358。电路别的部分有DC002与一个自锁开关构成电源电路,51单片机最小系统的复位电路,以及五个发光二极管作为功能实现的指示灯,LCD1602显示相关变量,两个排针引出输出波形,一个滑阻用来调整LCD1602的对比度,一个滑动变阻器用来调节LM358的输出电压。

温馨提示

这里给个温馨提示,如果对于波形发生器的要求是幅值0~5V,频率1~1000Hz,那咱这个设计方案,尽量查找一下资料优化一下,当然,咱这个电路设计方案也可以直接冲。

电路优化

先放一个嘉立创的电路原理图

在后面测试的过程中,我发现我的输出波形的幅值最大值只能达到3.5V左右。这是怎么回事呢?可能是因为鄙人在电路设计这方面过于肤浅了,嘛,毕竟本科在读两年半也没好好往电路这方面钻研过。上网查了一下LM358的数据手册。前面这个倒没什么,正常工作电压在正负20V来着。关键的是后面这个,其最大输出电压是VCC-1.5V ,而我给的VCC是5V,也就意味着我这块LM358能输出的最高电压本身只能达到3.5V。解决方案呢,我这有两个想法,一个是在电路中加一个升压电路,加个升压二极管之类的东西,或者是单独再加一个插口给LM358供电。当然啦,这边建议运算放大器用741,这就不用考虑这么多七的八的了,LM358双运算放大器也没什么好的(手动狗头)。

另一边就是没解决,也没想到解决方案的问题了。要是有人看到了这篇文章,并且知道怎么解决的话,还请评论留言,给我这小小的湖科大学子来个震撼(紧跟时事,好耶)。

另一个问题是关于频率的问题,我觉得是电路设计方案上的问题。我的程序是一组波形数据给了128个点,但是在调频的时候遇到了问题,不是不能调频,而是调不上去。基本上频率上了几十后,波形就会原地失真。而我把波形数据缩成八个点,勉强能看出有形状的时候,它大概能有个一两百的频率吧。当然,只给单片机IO输出高低电平,也就是只输出方波,调到个1KHz还是容易的。波形失真这应该属于模电这边的知识范畴吧。嗨嗨嗨,学的都挺一般的……所以说,该学习的时候还是得好好学习。

软件实现

波形数据实现,以正弦波为例。

首先,我们是将单片机的某位IO口连上数模转换芯片DAC0832上的,输出波形也就是单片机八位IO口输出高低电平,二进制对应起来就是0~255.0对应着输出电压0,255对应着输出电压5V。

用MATLAB计算需要的波形数据。

a=0:1:127;  %这里是想要得到128个点,0~127,共128个整数点。
b=127.5+sin(a*pi/64)*127.5; %sin 0 对应着255的一半,1对应255,-1对应0
y=b/5; %这里是将数据分成五等分,分别对应着0~5V六个档位,多出的一个为0
%再对y取整就可以将MATLAB里的数据直接复制粘贴了

然后是LCD1602,我这里的接线是将R/W接地了,也就是读取LCD1602状态这一点原地土遁,没法读取LCD1602的状态。但咱们也不咋需要读取LCD1602的状态,直接写指令数据到LCD1602就行了。

不过,这种接线跑上代码可能会遇到一种问题,就是第一行给你显示,第二行不显示。解决方法:

lcd_init(); //显示屏初始化
delay5ms(); 
lcd_init(); //再次初始化显示屏

我这边是初始化了两次显示屏就解决了这个问题,万一解决不了,那咱也只能摊手说,我也不清楚了。

五个按键

/********************°key**********************/
void key_contral(void)
{
    if(key1==0)
    {
        Delay5ms();
        if(key1==0)
        {
            led1=0;led2=1;led3=1;led4=1;led5=1;
            while(!key1);
            wave_chioce++; //这个choice是波形选择变量,每个数值对应一种波形
            if(wave_chioce==5)
                wave_chioce=0;
        }
    }
    if(key2==0)
    {
        Delay5ms();
        if(key2==0)
        {
            led1=1;led2=0;led3=1;led4=1;led5=1;
            while(!key2);
            rate++;
            if(rate>=25) rate=25;//这里的变量是设定调整频率的
            
        }
    }
    if(key3==0)
    {
        Delay5ms();
        if(key3==0)
        {
            led1=1;led2=1;led3=0;led4=1;led5=1;
            while(!key3);
            rate--;
            if(rate<=0)  rate=0;
            
        }
    }
    if(key4==0)
    {
        Delay5ms();
        if(key4==0)
        {
            led1=1;led2=1;led3=1;led4=0;led5=1;
            while(!key4);
            A=A+1;
            if(A==6)
                A=5;//这个A是设定调整幅值的,0~5对应0~5V
        }
    }
    if(key5==0)
    {
        Delay5ms();
        if(key5==0)
        {
            led1=1;led2=1;led3=1;led4=1;led5=0;
            while(!key5);
            A=A-1;
            if(A<0)
                A=0;
        }
    }
}

波形实现

用单片机定时器定时从P1(我设定的P1口)口输出数据。

在此之前在很前面的前面定义了#define DAC_OUT P1

定时器初始化,打开各级中断

我这里是中断中重装初值,输出波形数据,顺便把按键查询也放在中断中了,按键按下会更灵敏一点,可能?

void run_out() interrupt 1
    {
      static m,n,j;
        j=65536-16000/(1+39*(rate-1)); //计算计数初值,自个儿看着算
        m=j%256;//低八位
        n=j/256;//高八位
        TL0=m;
        TH0=n;
        alt++;
        if(alt==1)
        {
            switch(wave_chioce)
            {
                case 0:  DAC_OUT=A*sin[cnt]; break;
                case 1:  DAC_OUT=A*tan[cnt]; break;
                case 2:  DAC_OUT=A*rec[cnt]; break;
                case 3:  DAC_OUT=A*juc[cnt]; break;
                case 4:  DAC_OUT=A*lad[cnt]; break;
            }
        }
        cnt++;
        if(cnt>=128) cnt=0;
        key_contral();
    }

大致就这么多了。如果对您有帮助,那就最好不过了。

物联沃分享整理
物联沃-IOTWORD物联网 » 单片机课程设计:基于波形发生器的实现方案

发表评论