内容介绍
内容介绍
实现功能:
- Mic和Ain通道示波功能,有三个可调参数,能够调整采样速度和横纵轴的放大。
- Aux的波形输出,能够调整波形的类型(用定时器实现的方波和三角波)、频率和占空比。
- 配套上位机实现串口与单片机的通信,实现了简单的几个命令。
未完成内容:
- 首先未完成的是傅里叶变换功能,主要是ram空间问题。将CubeIDE仅生成adc的LL库,然后采样并参考jack的FFT库,利用FFT的计算函数进行运算,也会出现RAM不够的问题。希望有大佬能点拨点拨。
- 由于没有外围电路,所以没有实现波形输出正弦波(之前看到论坛上的方案是模拟函数,但是示波器测试了一下,并不是正弦波,不知道该怎么处理)
- 上位机没有实现波形显示功能。C#是现学的,adc方面可能存在上位机serialPort读取速率和缓存的问题,就没有搞下去。不过可以用开源的串口调试助手Vofa+,它自带了数据的波形显示。
实现过程:
上手前先去研究研究了jack的开源程序以及一些优秀的stm32示波器开源项目,有了大体的实现思路。由于是初次上手CubeIDE,对于cube的一些特性还不是很熟悉,只能边用边学。通过直播课,了解到LL库的优势,便尝试使用LL库,这也是一个新的知识。整个项目中都是在不断尝试新知识,不断摸索。
- oled驱动是直接找的别人已经开源的驱动,然后自己调整了下引脚初始化,加上了上部和下部的刷新函数,将示波界面的参数和波形分成两个区域进行单独的刷新,提高屏幕的稳定性和刷新速度。
//更新oled上部显存 void OLED_Refresh_12(void) { uint8_t i,n; for(i=0;i<2;i++) { OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址 OLED_WR_Byte(0x00,OLED_CMD); //设置低列起始地址 OLED_WR_Byte(0x10,OLED_CMD); //设置高列起始地址 for(n=0;n<128;n++) OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); } } //更新oled下部显存 void OLED_Refresh_345678(void) { uint8_t i,n; for(i=2;i<8;i++) { OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址 OLED_WR_Byte(0x00,OLED_CMD); //设置低列起始地址 OLED_WR_Byte(0x10,OLED_CMD); //设置高列起始地址 for(n=0;n<128;n++) OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); } }
- 按键检测采用常规的中断方式,用于交互界面,进入功能界面后连按两次ok键退出到初使界面。存在的一点问题是连按的时候,中断会进入多次,可以在中断之后加一个几十ms延迟解决这个问题。
- 串口使用了USART2,重定义printf到USART2,同时开启接收中断用于接收上位机的数据。中断中读取寄存器中的一个字节,根据该数据进行不同的功能选择,与自己写的上位机相匹配。
void USART2_IRQHandler(void) { /* USER CODE BEGIN USART2_IRQn 0 */ if(LL_USART_IsActiveFlag_RXNE(USART2)) { data=LL_USART_ReceiveData8(USART2); switch(data) { case 0: Fun_Flag=1; break; case 1: Fun_Flag=0; Fun_Value=1; break; case 2: Fun_Flag=0; Fun_Value=2; break; case 3: Fun_Flag=0; Fun_Value=3; break; case 4: Fun_Flag=0; Fun_Value=4; break; case 5: Fun_Flag=0; Fun_Value=5; break; case 6: Fun_Flag=0; Fun_Value=6; break; default:break; } LL_USART_TransmitData8(USART2, data); } /* USER CODE END USART2_IRQn 0 */ /* USER CODE BEGIN USART2_IRQn 1 */ /* USER CODE END USART2_IRQn 1 */ }
- 定时器部分,使用的LL库中没有us级延迟,故用TIM1设置了一个us的延迟函数用于adc的采样速度设置。还初使话了TIM2为PWM输出模式,用于生成方波。
void TIM1_uDelay(uint16_t us) { __HAL_TIM_SetCounter(&htim1, 0);//htim1 __HAL_TIM_ENABLE(&htim1); while(__HAL_TIM_GetCounter(&htim1) < (64 * us));//计数频率64MHz,64次即1us /* Disable the Peripheral */ __HAL_TIM_DISABLE(&htim1); }
- adc初使话为了单次转换,并且没有使用DMA传输数据(不用DMA的话,单次转换应该满足需要了),通过设置延迟时间来进行规律性的adc采样转换,保存到缓存数组中进行处理。在oled上显示了采样速度,横轴纵轴的倍率,实现波形的放大缩小。
//波形读取/显示函数 void Draw_BoXing(void) { uint8_t t; uint8_t x; //根据参数a,b自动调整横纵轴 for(t=1,x=1;t<(100/oscilldev.b)-1;t++,x+=oscilldev.b) { OLED_DrawLine_1(x,62-(double)(oscilldev.buffer[t])/4095/oscilldev.a*45,x+oscilldev.b,62-(double)(oscilldev.buffer[t+1])/4095/oscilldev.a*45); } //补画尾巴 OLED_DrawLine_1(x,62-(double)(oscilldev.buffer[t])/4095/oscilldev.a*45,100,62-(double)(oscilldev.buffer[t])/4095/oscilldev.a*45); }
/波形显示函数 void DrawOscillogram(uint8_t ch)//画波形图 { uint8_t t; if(oscilldev.flag == 0)//判断是否采集完 { oscilldev.flag = 1; //for(t=4;t<124;t++) for(t=1;t<(100/oscilldev.b);t++)//存储AD数值 { oscilldev.buffer[t] =Get_Adc(ch); //printf("%f\r\n",((float)(oscilldev.buffer[t])/4095*3.3)); if(oscilldev.tim==10000) LL_mDelay(10);//改变AD取样间隔 else TIM1_uDelay(oscilldev.tim); } OLED_Clear(); Draw_BianKuang(); Draw_GeZi(); Draw_BoXing(); OLED_Refresh_345678();//单刷新波形区域,不刷新上部 //OLED_Refresh(); LL_mDelay(50); oscilldev.flag = 0; } else ; //功能选择函数 if(KEY_Value != 254) { if(KEY_Value==L_Value)//对menu值的操作,进行选择移动 { if(menu>1)menu--; } if(KEY_Value==R_Value) { if(menu<3)menu++; } if(KEY_Value==U_Value)//根据menu进行不同的操作赋值 { if(menu==1) { if(oscilldev.tim>10)oscilldev.tim/=10; else if(oscilldev.tim==10)oscilldev.tim=1; } if(menu==2) { if(oscilldev.a<1)oscilldev.a+=0.2; } if(menu==3) { if(oscilldev.b==2)oscilldev.b=4; if(oscilldev.b==1)oscilldev.b=2; } } if(KEY_Value==D_Value) { if(menu == 1) { if(oscilldev.tim<10000)oscilldev.tim*=10; } if(menu == 2) { if(oscilldev.a>0.6)oscilldev.a-=0.2; } if(menu == 3) { if(oscilldev.b==2)oscilldev.b=1; if(oscilldev.b==4)oscilldev.b=2; } } if(KEY_Value==OK_Value)//连按两次ok返回功能选择界面 { KEY_Value=254; LL_mDelay(1000); if(KEY_Value==OK_Value) { Fun_Flag=1; OLED_Clear(); OLED_ShowString(10, 4, "wait...", 16, 1); OLED_Refresh(); LL_mDelay(1000); } } Draw_CanShu(); OLED_Refresh_12();//单刷新上部,不刷新波形区域 //OLED_Refresh(); KEY_Value=254; } }
- 上位机部分采用C#开发,功能比较简单,通过几个按钮,给单片机发送指定的字节,实现功能转换。
源码下载:
程序:链接:https://pan.baidu.com/s/1KAOS7wciKGL8-cRCQ7MC1A
提取码:zodq
二进制烧录文件:链接:https://pan.baidu.com/s/1ILy_WQ7AM_6rrDV0ijLVyw
提取码:ppap
上位机:链接:https://pan.baidu.com/s/19Lot_To_gIyktd0X4Ukk3w
提取码:d02r
附件下载
stm32g0_scope_V1.4发布.7z
程序主要源码,main中while仅留下了Mic示波函数
stm32g0_scope_V0.bin
二进制烧录文件
Mini_ScopeV0.7z
上位机程序源码,有可直接运行的exe
团队介绍
南京信息工程大学
电子信息类(3)班
团队成员
沈佳杰
长望学院
评论
0 / 100
查看更多
猜你喜欢
2021寒假在家一起练项目4——李小保一个完全使用FPGA来完成的综合性小项目
STEP-MAX10:基于Altera MAX10M02/08的FPGA学习板,带板载编程器
lxb
1614
WeDesign第4期:基于STM32G031核心模块的扩展板设计基于STM32G031的最小系统模块,运行Arm Cortex M0+内核,工作频率为64MHz,通过USB供电和配置,最多支持18个输入输出,其中6个可以为模拟输入。本期要求大家基于这个小模块,设计一款扩展板,并进行调试。
WeDesign
3323
FastBond2阶段1 - 基于STM32的运动手表基于STM32的运动手表是一款智能手表,具备多项功能和特点,适合运动爱好者使用。它集成了STM32微控制器,提供精确的运动数据监测、健康管理、智能通知等功能,为用户提供便捷的运动体验。
wangye
712