完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
|
|
相关推荐
1个回答
|
|
基本要求
(1)具有产生正弦波、方波、三角波三种周期性波形的功能。 (2)用键盘输入编辑生成上述三种波形(同周期)的线性组合波形,以及由基波及其谐波(5次以下)线性组合的波形。 (3)具有波形存储功能。 (4)输出波形的频率范围为100Hz~20kHz(非正弦波频率按10次谐波计算);重复频率可调,频率步进间隔≤100Hz。 (5)输出波形幅度范围0~5V(峰-峰值),可按步进0.1V(峰-峰值)调整。 (6)具有显示输出波形的类型、重复频率(周期)和幅度的功能。 拓展要求 (1)输出波形频率范围扩展至100Hz~200kHz。 (2)用键盘或其他输入装置产生任意波形。 (3)增加稳幅输出功能,当负载变化时,输出电压幅度变化不大于±10%(负载电阻变化范围:100Ω~∞)。 (4)具有掉电存储功能,可存储掉电前用户编辑的波形和设置。 (5)可产生单次或多次(1000次以下)特定波形(如产生1个半周期三角波输出)。 开机动画演示 GUI交互界面 波形输出实例 系统方案 通过对本题的分析,斟酌各个方案,最终确立了我们的最终方案。 (1) 波形采用STM32自带的DAC+DDS产生。 (2) 主控模块采用STM32F103单片机,控制整个系统的软硬件操作。 (3) 显示模块采用液晶显示器实时显示当前输出的波形的类型、幅值和频率。 (4) 按键模块采用独立按键的方式设置输出波形的类型、幅值和频率等数据。 1.1. 系统总体软件设计 软件架构图如下: 整个系统的交互采用按键和LCD显示屏实现。为了交互的更加便捷,本系统设计了多级的菜单界面,按键通过由菜单管理器切换菜单界面。菜单界面的底层是参数界面,参数界面用于设置和显示参数。设置的参数通过被放入参数管理器,可用于设置波形的频率和幅值。我们的设想是低频波形用单片机上的DAC实现,高频信号用AD8951也就是直接数字信号合成器合成产生波形。但是为了选择的多样性,无论高频还是低频,我们的DAC和DDS都会同时工作。 1.2. 交互模块 本系统的交互模块有需要用到LCD显示屏和按键。LCD显示模块主要由菜单显示模块和参数显示模块组成,分别由菜单管理器和参数管理器控制,通过按键设置菜单管理器和参数管理器的参数,可以设置显示不同的界面。参数管理器也是连接波形发生模块的桥梁。 下图为交互模块的程序框图: 1.3. DAC波形发生模块 本系统使用的是STM32F103里面自带的DAC。为了提高DAC转换的速度,使用DMA传输波形数据,DMA的触发传输使用的是定时器的中断。本系统使用的正弦波波形数据是通过C语言数学库math.h里面的函数sin()计算得到的数组,三角波通过自定义函数计算波形数据,这两个波形一个周期内采样了512个数据点;而方波的则不同,方波每个周期只改变两次DAC的值。当用户通过交互界面改变幅值参数时,会重新计算波形数据数组。当用户改变频率参数时,会重新计算DMA定时器的周期。波形的输出和关闭则是通过改变DMA定时器中断使能和DMA传输使能实现。 下图为DAC波形发生模块的程序框图: 1.4. DDS波形发生模块 DDS本身就是用来产生波形的,故要控制DDS产生波形,只需要设置DDS相应的寄存器就好了。 下图为DDS波形发生的程序框图: 代码实现 数据结构 参数管理器 typedef struct ParameterManagerStruct { bool isOutputEnable; ParameterSelected flagParaSelected; u32 am; u8 amArray[10]; u8 amArrayPoint; u8 amLen; u16 amCoordinateX; u16 amCoordinateY; u32 fq; u8 fqArray[10]; u8 fqArrayPoint; u8 fqLen; u16 fqCoordinateX; u16 fqCoordinateY; u32 har; u8 harArray[10]; u8 harArrayPoint; u8 harLen; u16 harCoordinateX; u16 harCoordinateY; } ParaMng; 菜单管理器 typedef enum MenuLayerEnum{ MenuLayer0=0, MenuLayer1, MenuLayer2 } MenuLayer; typedef struct MenuStruct{ MenuLayer layer; u8 Layer0_Selected; u8 Layer1_Selected; u8 Layer2_Selected; } Menu; 菜单项显示 typedef struct GUIMenuItem{ u8 *name; u8 fontSize; u32 fontColor; u32 backgroundColor; } GUI_Item; typedef struct GUIMenuTypedef { GUI_Item itemList[10]; u8 itemNum; u8 *topicName; } GUIMenu; 主函数 int main(void) { HAL_Init(); SystemClock_Config(); delay_init(72); MX_GPIO_Init(); MX_DMA_Init(); MX_DAC_Init(); MX_TIM2_Init(); MX_USART1_UART_Init(); MX_TIM4_Init(); MX_TIM3_Init(); MX_TIM6_Init(); LCD_Init();//LCD初始化 //菜单初始化 InitMenu(); InitParaManager();//参数初始化 menu.layer=MenuLayer0; menu.Layer0_Selected=Item_SignalGenerator; menu.Layer1_Selected=Item_SquareWave; menu.Layer2_Selected=Item_IsEnable; //开机动画 GUI_ShowPowerOn(); while(KEY_Scan(0)==0)delay_ms(20); //菜单显示 ShowMenu(); while (1) { //IRHandle(); KeyHandle();//按键处理 //ad9851去除干扰 ad9851_data_l; ad9851_fq_up_l; ad9851_rest_l; ad9851_w_clk_l; if(pm.flagParaSelected!=ParaRESET) ShowParameterNumber();//设置参数时界面显示 delay_ms(10); } } 按键处理 void KeyHandle(void) { u8 t=KEY_Scan(0); if(t>0){ switch(t){//按键扫描 case WKUP_PRES://按下“下”键 { if(pm.flagParaSelected==ParaRESET)//切换下一行 { if(menu.layer==MenuLayer0)menu.Layer0_Selected=(menu.Layer0_Selected+1)%ITEM_NUM_LAYER0; else if(menu.layer==MenuLayer1)menu.Layer1_Selected=(menu.Layer1_Selected+1)%ITEM_NUM_LAYER1; else if(menu.layer==MenuLayer2)menu.Layer2_Selected=(menu.Layer2_Selected+1)%ITEM_NUM_LAYER2; } else if(pm.flagParaSelected==ParaAM)//设置幅值状态, pm.amArrayPoint=(pm.amArrayPoint+1)%pm.amLen; else if(pm.flagParaSelected==ParaFQ)//设置频率状态 pm.fqArrayPoint=(pm.fqArrayPoint+1)%pm.fqLen; else if(pm.flagParaSelected==ParaHAR)//设置谐波状态 pm.harArrayPoint=(pm.harArrayPoint+1)%pm.harLen; } if(pm.flagParaSelected!=ParaRESET)ShowParameterNumber();//显示设置参数 break; //按下确认键 case KEY1_PRES: if(menu.layer==MenuLayer0)menu.layer=MenuLayer1; else if(menu.layer==MenuLayer1)menu.layer=MenuLayer2; else if(menu.layer==MenuLayer2)//在参数显示界面按下确认键 { if(menu.Layer2_Selected==Item_IsEnable){//打开或关闭信号输出 if(pm.isOutputEnable==false){ pm.isOutputEnable=true; EnableOutput(); } else{ pm.isOutputEnable=false; DisableOutput(); } } else if(menu.Layer2_Selected==Item_Amplitude)//幅值参数修改 { if(pm.flagParaSelected!=ParaAM) pm.flagParaSelected=ParaAM; else{ pm.flagParaSelected=ParaRESET; PM_SetValueFromArray(); SetAmplitude(); } } else if(menu.Layer2_Selected==Item_Frequency)//频率参数修改 { if(pm.flagParaSelected!=ParaFQ) pm.flagParaSelected=ParaFQ; else{ pm.flagParaSelected=ParaRESET; PM_SetValueFromArray(); SetFrequency(); } } else if(menu.Layer2_Selected==Item_Harmonic)//谐波参数修改 { if(pm.flagParaSelected!=ParaHAR) pm.flagParaSelected=ParaHAR; else pm.flagParaSelected=ParaRESET; } } break; //按下返回键 case KEY0_PRES: { if(pm.flagParaSelected==ParaRESET){//当前菜单状态,切换菜单 if(menu.layer==MenuLayer1) menu.layer=MenuLayer0; else if(menu.layer==MenuLayer2){ menu.layer=MenuLayer1; DisableOutput(); } } else if(pm.flagParaSelected==ParaAM)//当前在幅值设置状态,某一位增加 pm.amArray[pm.amArrayPoint]=(pm.amArray[pm.amArrayPoint]+1)%10; else if(pm.flagParaSelected==ParaFQ) pm.fqArray[pm.fqArrayPoint]=(pm.fqArray[pm.fqArrayPoint]+1)%10; else if(pm.flagParaSelected==ParaHAR) pm.harArray[pm.harArrayPoint]=(pm.harArray[pm.harArrayPoint]+1)%10; } //参数设置状态时,显示设置参数 if(pm.flagParaSelected!=ParaRESET)ShowParameterNumber(); break; } LED0_Toggle(); ShowMenuKeyUpdate(); } } 菜单显示更新函数 void ShowMenuKeyUpdate(void){ switch(menu.layer){//根据层数显示菜单 case MenuLayer0: LCD_Clear(WHITE); ShowLayer0();//显示根目录 break; case MenuLayer1: LCD_Clear(WHITE); switch(menu.Layer0_Selected){ case Item_SignalGenerator: ShowLayer1(); break; case Item_SoftWareAbout: ShowSoftwareAbout(); break; } break; case MenuLayer2: LCD_Clear(WHITE); switch(menu.Layer0_Selected){ case Item_SignalGenerator: ShowLayer2(); break; case Item_SoftWareAbout: ShowSoftwareAbout(); break; } break; } } DDS操作代码 #define ad9851_rest_l HAL_GPIO_WritePin(AD9851_RESET_GPIO_Port, AD9851_RESET_Pin, GPIO_PIN_RESET) #define ad9851_rest_h HAL_GPIO_WritePin(AD9851_RESET_GPIO_Port, AD9851_RESET_Pin, GPIO_PIN_SET) #define ad9851_fq_up_l HAL_GPIO_WritePin(AD9851_FQ_UP_GPIO_Port, AD9851_FQ_UP_Pin, GPIO_PIN_RESET) #define ad9851_fq_up_h HAL_GPIO_WritePin(AD9851_FQ_UP_GPIO_Port, AD9851_FQ_UP_Pin, GPIO_PIN_SET) #define ad9851_w_clk_l HAL_GPIO_WritePin(AD9851_W_CLK_GPIO_Port, AD9851_W_CLK_Pin, GPIO_PIN_RESET) #define ad9851_w_clk_h HAL_GPIO_WritePin(AD9851_W_CLK_GPIO_Port, AD9851_W_CLK_Pin, GPIO_PIN_SET) #define ad9851_data_l HAL_GPIO_WritePin(AD9851_DATA_GPIO_Port, AD9851_DATA_Pin, GPIO_PIN_RESET) #define ad9851_data_h HAL_GPIO_WritePin(AD9851_DATA_GPIO_Port, AD9851_DATA_Pin, GPIO_PIN_SET) //串行口初始化 void ad9851_reset_serial() { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = AD9851_RESET_Pin|AD9851_FQ_UP_Pin|AD9851_W_CLK_Pin|AD9851_DATA_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); ad9851_w_clk_l; ad9851_fq_up_l; ad9851_rest_l; ad9851_rest_h; ad9851_rest_l; ad9851_w_clk_l; ad9851_w_clk_h; ad9851_w_clk_l; ad9851_fq_up_l; ad9851_fq_up_h; ad9851_fq_up_l; } //串行口写入DDS寄存器 void ad9851_wr_serial(u8 w0,u32 frequence) { u8 i,w; frequence=frequence*4294967296/180000000; w=(frequence>>=0); for(i=0;i<8;i++) { if((w>>i)&0x01) ad9851_data_h; else ad9851_data_l; ad9851_w_clk_h; ad9851_w_clk_l; } w=(frequence>>8); for(i=0;i<8;i++) { if((w>>i)&0x01) ad9851_data_h; else ad9851_data_l; ad9851_w_clk_h; ad9851_w_clk_l; } w=(frequence>>16); for(i=0;i<8;i++) { if((w>>i)&0x01) ad9851_data_h; else ad9851_data_l; ad9851_w_clk_h; ad9851_w_clk_l; } w=(frequence>>24); for(i=0;i<8;i++) { if((w>>i)&0x01) ad9851_data_h; else ad9851_data_l; ad9851_w_clk_h; ad9851_w_clk_l; } w=w0; for(i=0;i<8;i++) { if((w>>i)&0x01) ad9851_data_h; else ad9851_data_l; ad9851_w_clk_h; ad9851_w_clk_l; } ad9851_fq_up_h; ad9851_fq_up_l; } 根据参数管理器设置DDS和DAC的频率 void SetFrequency(void) { //设置DDS频率 ad9851_reset_serial(); ad9851_wr_serial(0x01,pm.fq); //设置用于触发传输DAC-DMA的定时器中断时间 if(menu.Layer1_Selected==0) { if(pm.fq<=100){ TIM6->PSC=7199; TIM6->ARR=(u16)((10000/pm.fq)/2)-1;//不同的频率下 定时器的预分频系数不同 } else if(pm.fq<=10000) { TIM6->PSC=71; TIM6->ARR=(u16)((1000000/pm.fq)/2)-1; } else { TIM6->PSC=1; TIM6->ARR=(u16)((72000000/pm.fq)/2)-1; } } else if(menu.Layer1_Selected==1) { TIM6->PSC=71; TIM6->ARR=(u16)((1000000/pm.fq)/2)-1; } else if(menu.Layer1_Selected==2) { TIM6->PSC=71; TIM6->ARR=(u16)((1000000/pm.fq)/2)-1; } } 根据参数管理器设置Sine波形数据数组的值 void SetSineWaveData(void) { double d = 2.0*PI / 512.0; double t = (double)pm.am / 500000.0; int bias = 4096* pm.am / 500000.0/2; for (int i = 0; i < 512; i++) waveDataArray=(u16)(sin(i*d)*t*4096.0/2)+bias; } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1627 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1550 浏览 1 评论
984 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1601 浏览 2 评论
1869浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
651浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
520浏览 3评论
539浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
507浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 01:13 , Processed in 0.707182 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号