找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2961|回复: 1
收起左侧

函数信号发生器设计论文 uCOS-II多任务程序 AD9850+ARM1138+ARM1138

[复制链接]
ID:195456 发表于 2017-5-3 17:23 | 显示全部楼层 |阅读模式
这是我很早之前做的,大家可以看看,附件中包含有完整的论文和源码.
0.png
       采用基于DDS专用芯片AD9850作为信号产生模块,并以基于ARM7的微控制器ARM1138作为整个系统的控制核心。在ARM1138中嵌入UCOSII操作系统方便实现多任务处理。例如波形转换,频率调节,幅值调节,12864显示,I2C掉电保护等。本方案融合了如方案一频率合成的优点,并能发挥ARM控制器强大的系统管理能力。同时可利于分工合作,以最快的时间完成题目的所有要求。此方案比较灵活、可扩展性好,能完全达到设计要求,故采用此方案。

ARM微控制器从键盘获得控制信息,通过计算得到控制字并通过IO口送给DDS的频率和相位的控制端口,同时,将信息显示在LCD上。DDS输出信号由程序控制其预置频率和相位的正弦信号或方波信号,再通过放大倍数可调的运算放大系统来控制调幅。三角波则由方波信号经过一级方大后通过积分电路获得。掉电保护功能则由ARM1138内部AD把数据读回再通过I2C写入24C04来完成。结构图如图2-1。
0.png
2.2 DDS的实现设计
DDS的基本原理是利用采样定理,通过查表法产生波形,其基本架构如图2-2所示:
0.png
相位累加器由N位加法器与N位累加寄存器级联构成。 每来一个时钟脉冲fs,加法器将频率控制字k与累加寄存器输出的累加相位数据相加,把相加后的结果送至累加寄存器的数据输入端。累加寄存器将加法器在上一个时钟脉冲作用后所产生的新相位数据反馈到加法器的输入端,以使加法器在下一个时钟脉冲的作用下继续与频率控制字相加。这样,相位累加器在时钟作用下,不断对频率控制字进行线性相位累加。 由此可以看出, 相位累加器在每一个时钟脉冲输入时,把频率控制字累加一次,相位累加器输出的数据就是合成信号的相位,相位累加器的溢出频率就是DDS输出的信号频率。 用相位累加器输出的数据作为波形存储器(ROM)的相位取样地址,这样就可把存储在波形存储器内的波形抽样值 (二进制编码) 经查找表查出,完成相位到幅值转换。波形存储器的输出送到D/A转换器,D/A转换器将数字量形式的波形幅值转换成所要求合成频率的模拟量形式信号。低通滤波器用于滤除不需要的取样分量,以便输出频谱纯净的正弦波信号。 DDS在相对带宽、频率转换时间、高分辨力、相位连续性、 正交输出以及集成化等一系列性能指标方面远远超过了传统频率合成技术所能达到的水平,为系统提供了优于模拟信号源的性能。
0.png

系统测试
4.1测试条件
表1  仪器仪表
  
仪器仪表名称
  
型号
数量(台)
  
数字示波器
  
Tektronix
1
  
函数信号发生器
  
RIGOL
1
  
直流稳压电源
  
YB1732
1
  
万用表
  
DT9025
1
4.2测试方案与测试结果
       4.2.1观察示波器,记录频率值和输出电压峰-峰值。
表二    频率值和输出电压峰-峰值测量记录表
  
预置频率/Hz
  
测量频率/Hz
相对误差/%
峰-峰值/V
  
50
  
48
4
2
  
100
  
98
2
4
  
500
  
497
0.6
3
  
1k
  
1000
0
5
  
5k
  
4998
0.4
4
  
10k
  
9990
0.1
2
  
15k
  
15100
0.6
        3
  
20k
  
20108
0.54
1
4.2.2 观察示波器,记录步进频率值。
                              表三  步进频率值记录表
  
预置频率
  
Hz
  
步进值
  
(10Hz/步
测量频率
  
(Hz)
步进频率
  
Hz
相对误差
  
%
  
20
  
1
28
30
6
  
100
  
1
105
110
4.5
  
500
  
1
510
510
0
  
1k
  
1
1010
1010
0
  
5k
  
1
5010
5010
0
  
10k
  
1
10008
10010
0.019
  
15k
  
1
15015
15010
0.03
  
20k
  
1
20008
20010
0.009
4.3测试结果分析
    由实验调试结果及测试结果,该函数信号发生器达到了题目的所有指示要求,在选择波形与调节幅度频率试时采用LCD人机交互界面,界面友好方便,具有直观性。
五、结语
本次设计的低频三相信号源,主要运用了DDS基本原理,利用ARM1138作为仿真测试和实际测量(测量结果见上表)符合题目给定的基本要求。

本次软件设计流程如图3-1所示:程序初始化后进入初始界面,再判断KEY1是否被按下,按下KEY1是选择波形型号,按下KEY2选择频率递增,按下KEY3选择频率递减,按下KEY4选择幅值递增,按下KEY5选择幅值递减。本设计最大的优点就是能实现掉电保护,实时保存数据,防止电压过低或者突然断电造成的数据丢失。

源程序:
  1. /******************************/
  2. /******************************/

  3. #include <includes.h>
  4. #include  "AD9850.h"
  5. #define  SysCtlPeriEnable       SysCtlPeripheralEnable
  6. #define  SysCtlPeriDisable      SysCtlPeripheralDisable
  7. #define  GPIOPinTypeOut         GPIOPinTypeGPIOOutput
  8. #define  TASK_STK_SIZE                  64
  9. /**************************************
  10.   CONSTANTS 常量
  11. **************************************/

  12. /************************************
  13.   VARIABLES 变量
  14. *************************************/
  15. uint16 now_color=0;             //当前色
  16. uint16 state=0,flag=0;                 //状态
  17. uint16 frist_in=0;              //初次进入标志
  18. unsigned  char  num=0,aa=1;
  19. unsigned  int  tt;
  20. unsigned long ulData  =  0;
  21. unsigned  char  buff[5];
  22. unsigned  char  display[10];   
  23. float   temp=0;
  24. unsigned long dat= 0,dat2=0,dat3=0;
  25. unsigned  char wan=0, qian=0,ge=0,shi=0,bai=0;
  26. unsigned  char wan2=0, qian2=0,ge2=0,shi2=0,bai2=0;
  27. unsigned  char wan3=0, qian3=0,ge3=0,shi3=0,bai3=0;


  28. static OS_STK  GstkStart[TASK_START_STK_SIZE];//启动任务的堆栈   
  29. static OS_STK  GstkLED[TASK_LED_STK_SIZE];
  30. OS_STK        Task1Stk[TASK_STK_SIZE];
  31. OS_STK        Task2Stk[TASK_STK_SIZE];


  32. /*************************************
  33.    FUNCTION PROTOTYPES 函数声明
  34. **************************************/
  35. static void taskStart (void  *parg);          //启动任务
  36. static void taskLED(void *parg);              //任务0
  37. void  Task1(void *data);
  38. void  Task2(void *data);


  39. /***********************************************
  40.     功能:主程序
  41. ************************************************/
  42. int main (void)
  43. {
  44.     OSInit();                                 //  OS-II 初始化uC/OS-II的内核

  45.     OSTaskCreate( taskStart,                                          
  46.                   (void *)0,
  47.                   &GstkStart[TASK_START_STK_SIZE-1],
  48.                   TASK_START_PRIO );                    
  49.    /*  初始化启动任务   */       
  50.     OSStart();                                // 启动uC/OS-II*/

  51.     return(0);
  52. }


  53. /****************************************
  54. ** Function name:           Task_Start          
  55. ** input parameters:        *p_arg
  56. *****************************************/
  57. static void taskStart (void  *parg)
  58. {
  59.     (void)parg;

  60.     targetInit();                             // 初始化目标单片机     

  61.     #if OS_TASK_STAT_EN > 0
  62.     OSStatInit();                             // 使能统计功能
  63.     #endif
  64.    
  65.     /* 在这里创建其他任务 */
  66.     OSTaskCreate( taskLED,                                          
  67.                   (void *)0,
  68.                   &GstkLED[TASK_LED_STK_SIZE-1],
  69.                   TASK_LED_PRIO );            //  建处理任务
  70.     OSTaskCreate(Task1, (void *)2, &Task1Stk[TASK_STK_SIZE - 1],2);       
  71.     OSTaskCreate(Task2, (void *)3, &Task2Stk[TASK_STK_SIZE - 1], 3);
  72.    
  73.    
  74.     KEY_Init(KEY1 | KEY2); //按键初始化
  75.     LCDInit();   //LCD12864初始化                                               //  LCD初始化
  76.     clear_all(); // 清屏
  77.    
  78.     while (1)
  79.     {                             
  80.         /* 启动任务可在这里挂起  */
  81.        OSTaskSuspend(OS_PRIO_SELF);
  82.     }
  83. }


  84. /***********************************************
  85. 名称:任务0
  86. 功能:
  87. **********************************************/
  88. static void taskLED(void  *parg)
  89. {
  90.     (void)parg;
  91.     Display(ulData);//开机显示
  92.     for(;;)
  93.     {   
  94.         if(KEY_Get(KEY1))//KEY1选波形型号
  95.         {
  96.            OSTimeDlyHMSM(0,0,0,150);
  97.            if(KEY_Get(KEY1))
  98.            {
  99.               num++;
  100.               if(num==4)
  101.               {
  102.                 num=0;              
  103.               }   
  104.            }
  105.         }
  106.         
  107.         
  108.      
  109.       if(num==1)////正弦波
  110.       {
  111.         LCD_ComdWrite(0x93);
  112.         LCD_ComdWrite(0x0C);//关光标
  113.         Displaysin();//正弦波
  114.         dat=wan*10000+qian*1000+bai*100+shi*10;
  115.         Write_9850(dat);
  116.         display[4]=dat%100000/10000+0X30;//显示千位
  117.         display[3]=dat%10000/1000+0X30;//显示千位
  118.         display[2]=dat%1000/100+0X30;//显示百位
  119.         display[1]=dat%100/10+0X30;//显示十位
  120.         display[0]=dat%10+0X30;//显示个位
  121.            if(display[4]==0x30)
  122.            {
  123.              display[4]=0x20;
  124.             if(display[3]==0x30)        //高位为0,不显示
  125.             {
  126.                display[3]=0x20;              
  127.                if(display[2]==0x30)//次高位为0,不显示
  128.                {
  129.                display[2]=0x20;
  130.                if(display[1]==0x30)
  131.                display[1]=0x20;
  132.                }
  133.              }
  134.            }
  135.           LCD_ComdWrite(0x9B);
  136.           LCD_DataWrite(display[4]);
  137.           LCD_DataWrite(display[3]);
  138.           LCD_DataWrite(display[2]);
  139.           LCD_DataWrite(display[1]);
  140.           LCD_DataWrite(display[0]);
  141.          LCD_DataWrite('H');
  142.          LCD_DataWrite('Z');
  143.         if(KEY_Get(KEY2))//KEY2光标移动
  144.         {
  145.            OSTimeDlyHMSM(0,0,0,100);
  146.            if(KEY_Get(KEY2))
  147.            {
  148.                 //LCD_ComdWrite(0x9c);
  149.                 //LCD_ComdWrite(0x0F);//开光标显示
  150.                 //LCD_DataWrite(aa+0x30);
  151.                 shi++;
  152.                 if(shi==10)  
  153.                 {
  154.                   //aa=1;
  155.                   shi=0;
  156.                   bai++;
  157.                   if(bai==10)
  158.                   {
  159.                     bai=0;
  160.                     qian++;
  161.                     if(qian==10)
  162.                     {
  163.                       qian=0;
  164.                       wan++;
  165.                       if(wan==10)
  166.                       {
  167.                         wan=0;
  168.                       }
  169.                       dat=wan*10000+qian*1000+bai*100+shi*10;
  170.                       Write_9850(dat);  
  171.                     }
  172.                    dat=wan*10000+qian*1000+bai*100+shi*10;
  173.                    Write_9850(dat);   

  174.                   }
  175.                  dat=wan*10000+qian*1000+bai*100+shi*10;
  176.                  Write_9850(dat);
  177.                 }
  178.                   
  179.               dat=wan*10000+qian*1000+bai*100+shi*10;
  180.               Write_9850(dat);   
  181.                
  182.             }
  183.            display[4]=dat%100000/10000+0X30;//显示千位
  184.            display[3]=dat%10000/1000+0X30;//显示千位
  185.            display[2]=dat%1000/100+0X30;//显示百位
  186.            display[1]=dat%100/10+0X30;//显示十位
  187.            display[0]=dat%10+0X30;//显示个位
  188.            if(display[4]==0x30)
  189.            {
  190.              display[4]=0x20;
  191.             if(display[3]==0x30)        //高位为0,不显示
  192.             {
  193.                display[3]=0x20;              
  194.                if(display[2]==0x30)//次高位为0,不显示
  195.                {
  196.                     display[2]=0x20;
  197.                     if(display[1]==0x30)
  198.                       display[1]=0x20;
  199.                }
  200.              }
  201.            }
  202.           LCD_ComdWrite(0x9B);
  203.           LCD_DataWrite(display[4]);
  204.           LCD_DataWrite(display[3]);
  205.           LCD_DataWrite(display[2]);
  206.           LCD_DataWrite(display[1]);
  207.           LCD_DataWrite(display[0]);
  208.           LCD_DataWrite('H');
  209.           LCD_DataWrite('Z');
  210.         }
  211.       }////正弦波
  212.       
  213.       
  214.       if(num==2)//  显示方波
  215.       {
  216.          LCD_ComdWrite(0x93);
  217.          LCD_ComdWrite(0x0C);//关光标
  218.          Displayfang();//  显示方波
  219.          dat2=wan2*10000+qian2*1000+bai2*100+shi2*10;
  220.          Write_9850(dat2);
  221.          display[4]=dat2%100000/10000+0X30;//显示千位
  222.            display[3]=dat2%10000/1000+0X30;//显示千位
  223.           display[2]=dat2%1000/100+0X30;//显示百位
  224.           display[1]=dat2%100/10+0X30;//显示十位
  225.           display[0]=dat2%10+0X30;//显示个位
  226.            if(display[4]==0x30)
  227.            {
  228.              display[4]=0x20;
  229.             if(display[3]==0x30)        //高位为0,不显示
  230.             {
  231.                display[3]=0x20;              
  232.                if(display[2]==0x30)//次高位为0,不显示
  233.                {
  234.                     display[2]=0x20;
  235.                     if(display[1]==0x30)
  236.                       display[1]=0x20;
  237.                }
  238.              }
  239.            }
  240.           LCD_ComdWrite(0x9B);
  241.           LCD_DataWrite(display[4]);
  242.           LCD_DataWrite(display[3]);
  243.           LCD_DataWrite(display[2]);
  244.           LCD_DataWrite(display[1]);
  245.           LCD_DataWrite(display[0]);
  246.           LCD_DataWrite('H');
  247.           LCD_DataWrite('Z');
  248.         if(KEY_Get(KEY2))//KEY2光标移动
  249.         {
  250.            OSTimeDlyHMSM(0,0,0,100);
  251.            if(KEY_Get(KEY2))
  252.            {
  253.                 //LCD_ComdWrite(0x9c);
  254.                 //LCD_ComdWrite(0x0F);//开光标显示
  255.                 //LCD_DataWrite(aa+0x30);
  256.                 shi2++;
  257.                 if(shi2==10)  
  258.                 {
  259.                   //aa=1;
  260.                   shi2=0;
  261.                   bai2++;
  262.                   if(bai2==10)
  263.                   {
  264.                     bai2=0;
  265.                     qian2++;
  266.                     if(qian2==10)
  267.                     {
  268.                       qian2=0;
  269.                       wan2++;
  270.                       if(wan2==10)
  271.                       {
  272.                         wan2=0;
  273.                       }
  274.                       dat2=wan2*10000+qian2*1000+bai2*100+shi2*10;
  275.                       Write_9850(dat2);  
  276.                     }
  277.                     dat2=wan2*10000+qian2*1000+bai2*100+shi2*10;
  278.                     Write_9850(dat2);   

  279.                   }
  280.                   dat2=wan2*10000+qian2*1000+bai2*100+shi2*10;
  281.                   Write_9850(dat2);
  282.                 }
  283.                   
  284.               dat2=wan2*10000+qian2*1000+bai2*100+shi2*10;
  285.               Write_9850(dat2);   
  286.                
  287.             }
  288.            display[4]=dat2%100000/10000+0X30;//显示千位
  289.            display[3]=dat2%10000/1000+0X30;//显示千位
  290.           display[2]=dat2%1000/100+0X30;//显示百位
  291.           display[1]=dat2%100/10+0X30;//显示十位
  292.           display[0]=dat2%10+0X30;//显示个位
  293.            if(display[4]==0x30)
  294.            {
  295.              display[4]=0x20;
  296.             if(display[3]==0x30)        //高位为0,不显示
  297.             {
  298.                display[3]=0x20;              
  299.                if(display[2]==0x30)//次高位为0,不显示
  300.                {
  301.                     display[2]=0x20;
  302.                     if(display[1]==0x30)
  303.                       display[1]=0x20;
  304.                }
  305.              }
  306.            }
  307.           LCD_ComdWrite(0x9B);
  308.           LCD_DataWrite(display[4]);
  309.           LCD_DataWrite(display[3]);
  310.           LCD_DataWrite(display[2]);
  311.           LCD_DataWrite(display[1]);
  312.           LCD_DataWrite(display[0]);
  313.           LCD_DataWrite('H');
  314.           LCD_DataWrite('Z');
  315.         }
  316.       }//  显示方波
  317.       
  318.       
  319.       
  320.        if(num==3)//  显示三角波
  321.       {
  322.         LCD_ComdWrite(0x93);
  323.         LCD_ComdWrite(0x0C);//关光标
  324.         Displaythree();//  显示三角波
  325.         dat3=wan3*10000+qian3*1000+bai3*100+shi3*10;
  326.         Write_9850(dat3);
  327.         display[4]=dat3%100000/10000+0X30;//显示千位
  328.         display[3]=dat3%10000/1000+0X30;//显示千位
  329.         display[2]=dat3%1000/100+0X30;//显示百位
  330.         display[1]=dat3%100/10+0X30;//显示十位
  331.         display[0]=dat3%10+0X30;//显示个位
  332.         if(display[4]==0x30)
  333.         {
  334.             display[4]=0x20;//高位为0,不显示
  335.             if(display[3]==0x30)        //高位为0,不显示
  336.             {
  337.                display[3]=0x20;              
  338.                if(display[2]==0x30)//次高位为0,不显示
  339.                {
  340.                     display[2]=0x20;
  341.                     if(display[1]==0x30)
  342.                       display[1]=0x20;
  343.                }
  344.              }
  345.            }
  346.           LCD_ComdWrite(0x9B);
  347.           LCD_DataWrite(display[4]);
  348.           LCD_DataWrite(display[3]);
  349.           LCD_DataWrite(display[2]);
  350.           LCD_DataWrite(display[1]);
  351.           LCD_DataWrite(display[0]);
  352.           LCD_DataWrite('H');
  353.           LCD_DataWrite('Z');
  354.         if(KEY_Get(KEY2))//KEY2光标移动
  355.         {
  356.            OSTimeDlyHMSM(0,0,0,100);
  357.            if(KEY_Get(KEY2))
  358.            {
  359.                 //LCD_ComdWrite(0x9c);
  360.                 //LCD_ComdWrite(0x0F);//开光标显示
  361.                 //LCD_DataWrite(aa+0x30);
  362.                 shi3++;
  363.                 if(shi3==10)  
  364.                 {
  365.                   shi3=0;
  366.                   bai3++;
  367.                   if(bai3==10)
  368.                   {
  369.                     bai3=0;
  370.                     qian3++;
  371.                     if(qian3==10)
  372.                     {
  373.                       qian3=0;
  374.                       wan3++;
  375.                       if(wan3==10)
  376.                       {
  377.                         wan3=0;
  378.                       }
  379.                       dat3=wan3*10000+qian3*1000+bai3*100+shi3*10;
  380.                       Write_9850(dat3);  
  381.                     }
  382.                     dat3=wan3*10000+qian3*1000+bai3*100+shi3*10;
  383.                     Write_9850(dat3);   

  384.                   }
  385.                   dat3=wan3*10000+qian3*1000+bai3*100+shi3*10;
  386.                    Write_9850(dat3);
  387.                 }
  388.                   
  389.                dat3=wan3*10000+qian3*1000+bai3*100+shi3*10;
  390.               Write_9850(dat3);   
  391.                
  392.             }
  393.            display[4]=dat3%100000/10000+0X30;//显示千位
  394.            display[3]=dat3%10000/1000+0X30;//显示千位
  395.            display[2]=dat3%1000/100+0X30;//显示百位
  396.            display[1]=dat3%100/10+0X30;//显示十位
  397.            display[0]=dat3%10+0X30;//显示个位
  398.            if(display[4]==0x30)
  399.            {
  400.              display[4]=0x20;
  401.             if(display[3]==0x30)        //高位为0,不显示
  402.             {
  403.                display[3]=0x20;              
  404.                if(display[2]==0x30)//次高位为0,不显示
  405.                {
  406.                display[2]=0x20;
  407.                if(display[1]==0x30)
  408.                display[1]=0x20;
  409.                }
  410.              }
  411.            }
  412.           LCD_ComdWrite(0x9B);
  413.           LCD_DataWrite(display[4]);
  414.           LCD_DataWrite(display[3]);
  415.           LCD_DataWrite(display[2]);
  416.           LCD_DataWrite(display[1]);
  417.           LCD_DataWrite(display[0]);
  418.           LCD_DataWrite('H');
  419.           LCD_DataWrite('Z');
  420.         }
  421.       }  //  显示三角波
  422.     }
  423. }
  424. /**********************************************************
  425. 名称:Task1()
  426. 功能:执行相应功能
  427. ***********************************************************/
  428. void  Task1(void *pdata)
  429. {  
  430.    pdata=pdata;
  431.     while(1)           
  432.     {       
  433.       if(state==0)
  434.       {
  435.           temp=4.8;
  436.           tt=temp*10;
  437.           buff[0]=tt/10+0x30;
  438.           buff[1]=tt%10+0x30;
  439.           LCD_ComdWrite(0x8B);
  440.           LCD_DataWrite(buff[0]);
  441.           LCD_DataWrite('.');
  442.           LCD_DataWrite(buff[1]);
  443.           LCD_DataWrite('V');
  444.           //LED_Toggle(LED1);
  445.           state=1;   
  446.       }
  447.     }
  448. }
  449. /****************************************
  450. 名称:Task2()
  451. 功能:按键控制
  452. *****************************************/
  453. void  Task2(void *pdata)
  454. {   
  455.     pdata=pdata;
  456.    
  457.     while(1)
  458.     {  
  459.       if(flag==0)
  460.       {
  461.           LED_Toggle(LED3);
  462.           flag=1;
  463. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

下载:
函数信号发生器多任务程序(完成2 24C02).rar (220.1 KB, 下载次数: 20)

评分

参与人数 1黑币 +5 收起 理由
liaoyx0214 + 5 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:559107 发表于 2019-6-25 15:23 | 显示全部楼层
这个怎么样啊
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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