
开源协议
:GPL 3.0
描述
开源协议
GPL V3.0
- GPL的条款和条件必须提供给任何接受GPL应用的作品的副本(“被许可人”)的人员。
- 任何遵守条款和条件的被授证人员都有权修改作品,以及复制和重新分发作品或任何派生版本。
- GPL下的软件可以用于所有目的,包括商业目的,甚至作为创建专有软件的工具,例如使用GPL许可的编译器时,分发 GPL许可作品(如软件)的用户或公司可能会收取副本费用或无偿提供费用。
项目参数
- 使用GD32F407天空星开发板作为系统主控,进行官方标准库软件适配
- 使用AD9910 DDS作为信号发生器源,工作频率1GHz,可产生480MHz正弦
- 实现任意波形生成,数字斜坡扫频,可调频调幅调相
- 采用2.4寸lcd屏与六个按键实现菜单操作
- 使用lvgl库实现gui,使用SPI+DMA+双缓存,最大程度优化性能
实物展示
原理图设计
电源框架
AD9910需要的电源域比较复杂,整个系统主要分为6路电源
5V主电源:typec口或插座提供5V输入,经过双磁珠电容滤波后,用于给开发板供电以及后级的降压电路
3.3V主电源:由5V经过SY8113BADC DCDC降压得到,用于屏幕等供电
3.3V模拟电源与数字电源: 由3.3V主电源经过磁珠隔离得来,用于AD9910的AVDD3V3,DVDD3V3供电
1.8V模拟电源与数字电源: 由3.3V主电源经过两路TP5108 LDO降压得到,用于AD9910的AVDD1V8,DVDD1V8供电
时钟源
AD9910使用一个外部时钟源输入,这里使用40MHz有源晶振,3.3V经过磁珠后供电
输出滤波电路
DDS输出需要经过LC低通滤波电路,DDS系统中的基本输出频率高阶谐波会因混叠而折回至基带,使用低通滤波过滤高频谐波分量,会产生一定相移,导致两端输出并不是完全的180度差分
其他
剩下的一些设计是2.4寸屏幕,六个按键,引出的排针等等
PCB设计
本项目涉及的频率较高,PCB使用了四层板,中间一层铺模拟地,其余全铺GND,本人经验不足,如有错误欢迎指出
有一些值得注意的点:
晶振部分做了包地打过孔,以及裸露禁止铺铜的处理
DCDC的布局走线参考与数据手册,主要使用填充区域走线
AD9910支持并行输入,因开发板限制,本项目使用的是串行输入,但是这里把并口也引出排针,并做了等长组处理
软件设计
软件层面主要包括四个部分:GD32F407驱动,AD9910驱动,LVGL驱动,GUI菜单
这里只是介绍框架,详细内容请看附件中的工程代码
GD32F407驱动
本项目使用官方下载的标准库,涉及的外设为GPIO,SPI,DMA,TIMER等等,更详细的GD32资料可以去开发板文档查阅学习:https://wiki.lckfb.com/zh-hans/
引脚以及外设配置可以查看官方数据手册与标准库中的example
为了达到最大性能的屏幕显示,重点在于spi与dma的使用
void LCD_SPI_Init(void)
{
/* 开启各引脚时钟 */
rcu_periph_clock_enable(RCU_LCD_SCL);
rcu_periph_clock_enable(RCU_LCD_SDA);
rcu_periph_clock_enable(RCU_LCD_CS);
rcu_periph_clock_enable(RCU_LCD_DC);
rcu_periph_clock_enable(RCU_LCD_RES);
/* 使能SPI */
rcu_periph_clock_enable(RCU_SPI_HARDWARE);
/* 配置 SPI的SCK GPIO */
gpio_af_set(PORT_LCD_SCL, LINE_AF_SPI, GPIO_LCD_SCL);
gpio_mode_set(PORT_LCD_SCL, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_LCD_SCL);
gpio_output_options_set(PORT_LCD_SCL, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_SCL);
gpio_bit_set(PORT_LCD_SCL,GPIO_LCD_SCL);
/* 配置 SPI的MOSI GPIO */
gpio_af_set(PORT_LCD_SDA, LINE_AF_SPI, GPIO_LCD_SDA);
gpio_mode_set(PORT_LCD_SDA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_LCD_SDA);
gpio_output_options_set(PORT_LCD_SDA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_LCD_SDA);
gpio_bit_set(PORT_LCD_SDA, GPIO_LCD_SDA);
/* 配置DC */
gpio_mode_set(PORT_LCD_DC,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,GPIO_LCD_DC);
gpio_output_options_set(PORT_LCD_DC,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_LCD_DC);
gpio_bit_write(PORT_LCD_DC, GPIO_LCD_DC, SET);
/* 配置RES */
gpio_mode_set(PORT_LCD_RES,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,GPIO_LCD_RES);
gpio_output_options_set(PORT_LCD_RES,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_LCD_RES);
gpio_bit_write(PORT_LCD_RES, GPIO_LCD_RES, SET);
/* 配置CS */
gpio_mode_set(PORT_LCD_CS,GPIO_MODE_OUTPUT,GPIO_PUPD_PULLUP,GPIO_LCD_CS);
gpio_output_options_set(PORT_LCD_CS,GPIO_OTYPE_PP,GPIO_OSPEED_50MHZ,GPIO_LCD_CS);
gpio_bit_write(PORT_LCD_CS, GPIO_LCD_CS, SET);
/* 配置 SPI 参数 */
spi_parameter_struct spi_init_struct;
spi_i2s_deinit(SPI0);
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; // 传输模式全双工
spi_init_struct.device_mode = SPI_MASTER; // 配置为主机
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT; // 8位数据
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
spi_init_struct.nss = SPI_NSS_SOFT; // 软件cs
spi_init_struct.prescale = SPI_PSC_2;//2分频
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI0, &spi_init_struct);
/* 使能 SPI */
spi_enable(SPI0);
spi_dma_enable(SPI0,SPI_DMA_TRANSMIT);
rcu_periph_clock_enable(BSP_DMA_RCU);
/* SPI0 transmit dma config:DMA1-DMA_CH3 */
dma_deinit(DMA1, DMA_CH5);
dma_init_struct.periph_addr = (uint32_t)(&SPI_DATA(SPI0));
dma_init_struct.memory0_addr = 0;
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init_struct.number = 0;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
dma_single_data_mode_init(DMA1, DMA_CH5, &dma_init_struct);
/* configure DMA mode */
dma_channel_subperipheral_select(DMA1, DMA_CH5, DMA_SUBPERI3);
dma_channel_disable(DMA1,DMA_CH5);
}
GD32允许SPI配置了DMA后不使用DMA而直接SPI发送,故我们更改LCD的读写逻辑:对于少量数据如寄存器配置,发送指令等等,采用硬件spi直接发送;对于LVGL屏幕周期刷新任务,数据量较大,采用DMA一次性发送
两个发送函数:
void SPI_Transmit_DMA(uint8_t* data,uint32_t Size)
{
swap_high_low_8bits(data, Size);//交换每一个16位颜色数据中的高八位与第八位,否则LVGL色彩会有bug,应当视实际情况调试
dma_init_struct.memory0_addr = (uint32_t)data;
dma_init_struct.number = Size;
dma_single_data_mode_init(DMA1, DMA_CH5, &dma_init_struct);
dma_channel_enable(DMA1,DMA_CH5);
while(dma_flag_get(DMA1,DMA_CH5,DMA_FLAG_FTF)!= SET){}
dma_flag_clear(DMA1,DMA_CH5,DMA_FLAG_FTF);
dma_channel_disable(DMA1,DMA_CH5);
}
void SPI_Transmit(uint8_t* data,uint32_t Size){
for(int i=0;ix2 - area->x1 + 1) * (area->y2 - area->y1 + 1) * 2;
LCD_Address_Set(area->x1, area->y1, area->x2, area->y2);
LCD_CS_Clr();
SPI_Transmit_DMA((uint8_t*)color_p,size);
LCD_CS_Set();
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
AD9910驱动
整体使用GPIO模拟硬件SPI时序的方式驱动AD9910,对于需要动态改变的工作参数来说,驱动程序还需要支持快速调整DDS工作参数的功能,这可以通过修改内部的频率控制字(FCW)来实现。
驱动AD9910的第一步是要对其进行初始化和配置。这包括但不限于设置工作模式、输出频率、相位偏移、输出幅度等。驱动程序首先包含初始化函数,确保AD9910在启动时能够正确配置。
void AD9910_IOInit(void)
{
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_GPIOD);
rcu_periph_clock_enable(RCU_GPIOE);
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, (GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9));
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, (GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9));
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_0);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, (GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7));
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, (GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7));
gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3));
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3));
}
void Init_AD9910(void)
{
uchar k, m;
AD9910_IOInit();//IO初始化
AD9910_PWR_0;//软件拉低
PROFILE2_0;
PROFILE1_0;
PROFILE0_0;
DRCTL_0;
DRHOLD_0;
MAS_REST_1;
delay_ms(5);
MAS_REST_0;
CS_0;
txd_8bit(0x00); //发送CFR1控制字地址
for (m = 0; m < 4; m++)
txd_8bit(cfr1[m]);
CS_1;
for (k = 0; k < 10; k++);
CS_0;
txd_8bit(0x01); //发送CFR2控制字地址
for (m = 0; m < 4; m++)
txd_8bit(cfr2[m]);
CS_1;
for (k = 0; k < 10; k++);
CS_0;
txd_8bit(0x02); //发送CFR3控制字地址
for (m = 0; m < 4; m++)
txd_8bit(cfr3[m]);
CS_1;
for (k = 0; k < 10; k++);
UP_DAT_1;
for(k = 0; k < 10; k++);
UP_DAT_0;
delay_ms(1);
}
AD官方还发过AD9910的评估软件,可以用来菜单化操作,通过配置生成内部寄存器的值
链接:https://www.analog.com/cn/resources/evaluation-hardware-and-software/evaluation-boards-kits/EVAL-AD9910.html
GUI菜单
GUI的设计使用NXP的GUIGUIDER软件,免费但是功能可能没有squareline studio多,菜单采用多级菜单的形式,例如主界面->波形生成->正弦波。
GUI制作用到了开源的GUI图形库LVGL,主要使用了Label、Button、Spinbox等控件。关于人机交互,则是使用主板上的五个按键,可以实现界面跳转,功能选择以及波形参数的配置。
void setup_scr_MainScreen(lv_ui *ui)
{
//Write codes MainScreen
ui->MainScreen = lv_obj_create(NULL);
lv_obj_set_size(ui->MainScreen, 320, 240);
lv_obj_set_scrollbar_mode(ui->MainScreen, LV_SCROLLBAR_MODE_OFF);
//Write style for MainScreen, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT.
lv_obj_set_style_bg_opa(ui->MainScreen, 255, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui->MainScreen, lv_color_hex(0xffcfb0), LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_grad_dir(ui->MainScreen, LV_GRAD_DIR_NONE, LV_PART_MAIN|LV_STATE_DEFAULT);
//Write codes MainScreen_label_1
ui->MainScreen_label_1 = lv_label_create(ui->MainScreen);
lv_label_set_text(ui->MainScreen_label_1, "AD9910\nWaveGenerator");
lv_label_set_long_mode(ui->MainScreen_label_1, LV_LABEL_LONG_WRAP);
lv_obj_set_pos(ui->MainScreen_label_1, 73, 33);
lv_obj_set_size(ui->MainScreen_label_1, 174, 41);
//Write style for MainScreen_label_1, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT.
lv_obj_set_style_border_width(ui->MainScreen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_radius(ui->MainScreen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_color(ui->MainScreen_label_1, lv_color_hex(0x000000), LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ui->MainScreen_label_1, &lv_font_SourceHanSerifSC_Regular_18, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_opa(ui->MainScreen_label_1, 255, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_letter_space(ui->MainScreen_label_1, 2, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_line_space(ui->MainScreen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_align(ui->MainScreen_label_1, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(ui->MainScreen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_pad_top(ui->MainScreen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_pad_right(ui->MainScreen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_pad_bottom(ui->MainScreen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_pad_left(ui->MainScreen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_shadow_width(ui->MainScreen_label_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
//Write codes MainScreen_btn_1
ui->MainScreen_btn_1 = lv_btn_create(ui->MainScreen);
ui->MainScreen_btn_1_label = lv_label_create(ui->MainScreen_btn_1);
lv_label_set_text(ui->MainScreen_btn_1_label, "WaveGenerate");
lv_label_set_long_mode(ui->MainScreen_btn_1_label, LV_LABEL_LONG_WRAP);
lv_obj_align(ui->MainScreen_btn_1_label, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_pad_all(ui->MainScreen_btn_1, 0, LV_STATE_DEFAULT);
lv_obj_set_width(ui->MainScreen_btn_1_label, LV_PCT(100));
lv_obj_set_pos(ui->MainScreen_btn_1, 83, 92);
lv_obj_set_size(ui->MainScreen_btn_1, 159, 24);
//Write style for MainScreen_btn_1, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT.
lv_obj_set_style_bg_opa(ui->MainScreen_btn_1, 255, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui->MainScreen_btn_1, lv_color_hex(0xff6500), LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_grad_dir(ui->MainScreen_btn_1, LV_GRAD_DIR_NONE, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_border_width(ui->MainScreen_btn_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_radius(ui->MainScreen_btn_1, 5, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_shadow_width(ui->MainScreen_btn_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_color(ui->MainScreen_btn_1, lv_color_hex(0x000000), LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ui->MainScreen_btn_1, &lv_font_montserratMedium_16, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_opa(ui->MainScreen_btn_1, 255, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_align(ui->MainScreen_btn_1, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN|LV_STATE_DEFAULT);
//Write codes MainScreen_btn_2
ui->MainScreen_btn_2 = lv_btn_create(ui->MainScreen);
ui->MainScreen_btn_2_label = lv_label_create(ui->MainScreen_btn_2);
lv_label_set_text(ui->MainScreen_btn_2_label, "Modulate");
lv_label_set_long_mode(ui->MainScreen_btn_2_label, LV_LABEL_LONG_WRAP);
lv_obj_align(ui->MainScreen_btn_2_label, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_pad_all(ui->MainScreen_btn_2, 0, LV_STATE_DEFAULT);
lv_obj_set_width(ui->MainScreen_btn_2_label, LV_PCT(100));
lv_obj_set_pos(ui->MainScreen_btn_2, 83, 134);
lv_obj_set_size(ui->MainScreen_btn_2, 159, 24);
//Write style for MainScreen_btn_2, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT.
lv_obj_set_style_bg_opa(ui->MainScreen_btn_2, 255, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui->MainScreen_btn_2, lv_color_hex(0xff6500), LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_grad_dir(ui->MainScreen_btn_2, LV_GRAD_DIR_NONE, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_border_width(ui->MainScreen_btn_2, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_radius(ui->MainScreen_btn_2, 5, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_shadow_width(ui->MainScreen_btn_2, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_color(ui->MainScreen_btn_2, lv_color_hex(0x000000), LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ui->MainScreen_btn_2, &lv_font_montserratMedium_16, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_opa(ui->MainScreen_btn_2, 255, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_align(ui->MainScreen_btn_2, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN|LV_STATE_DEFAULT);
//Write codes MainScreen_btn_3
ui->MainScreen_btn_3 = lv_btn_create(ui->MainScreen);
ui->MainScreen_btn_3_label = lv_label_create(ui->MainScreen_btn_3);
lv_label_set_text(ui->MainScreen_btn_3_label, "FreqSweep");
lv_label_set_long_mode(ui->MainScreen_btn_3_label, LV_LABEL_LONG_WRAP);
lv_obj_align(ui->MainScreen_btn_3_label, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_style_pad_all(ui->MainScreen_btn_3, 0, LV_STATE_DEFAULT);
lv_obj_set_width(ui->MainScreen_btn_3_label, LV_PCT(100));
lv_obj_set_pos(ui->MainScreen_btn_3, 83, 176);
lv_obj_set_size(ui->MainScreen_btn_3, 159, 24);
//Write style for MainScreen_btn_3, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT.
lv_obj_set_style_bg_opa(ui->MainScreen_btn_3, 255, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(ui->MainScreen_btn_3, lv_color_hex(0xff6500), LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_bg_grad_dir(ui->MainScreen_btn_3, LV_GRAD_DIR_NONE, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_border_width(ui->MainScreen_btn_3, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_radius(ui->MainScreen_btn_3, 5, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_shadow_width(ui->MainScreen_btn_3, 0, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_color(ui->MainScreen_btn_3, lv_color_hex(0x000000), LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ui->MainScreen_btn_3, &lv_font_montserratMedium_16, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_opa(ui->MainScreen_btn_3, 255, LV_PART_MAIN|LV_STATE_DEFAULT);
lv_obj_set_style_text_align(ui->MainScreen_btn_3, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN|LV_STATE_DEFAULT);
//The custom code of MainScreen.
lv_group_focus_obj(ui->MainScreen_btn_1);
//Update current screen layout.
lv_obj_update_layout(ui->MainScreen);
//绑定组1和设备
groupRect_MainScreen = lv_group_create(); //创建组1
//挂载组1的控件,包括加减按钮以及指向下一个界面的按钮
lv_group_add_obj(groupRect_MainScreen,ui->MainScreen_btn_1);
lv_group_add_obj(groupRect_MainScreen,ui->MainScreen_btn_2);
lv_group_add_obj(groupRect_MainScreen,ui->MainScreen_btn_3);
//绑定外部设备
lv_indev_set_group(indev_keypad,groupRect_MainScreen);
//Init events for screen.
events_init_MainScreen(ui);
}
注意事项
AD9910芯片价格比较高,本项目的芯片来源于某宝购买,测试使用无问题,一般价格不会低于100
开发板与扩展版安装方式:
参考项目
感谢大佬的开源贡献:https://oshwhub.com/cheerfulness/Oscilloscope-and-High-Frequency-Signal-Generator-Based-on-STM32
设计图

BOM


评论