当前位置:网站首页>电设3----脉冲信号测试仪
电设3----脉冲信号测试仪
2022-08-02 14:19:00 【FX.STU】
目录
一、课设题目和要求
设计制作一个脉冲信号测试仪,可以测量脉冲信号的幅值、频率、周期。
基础要求:
1. 实现信号幅度测量,被测信号幅度范围为:0.5VP~5VP,测量精度≤±5%。
2. 实现信号频率和周期测量,被测信号频率范围为:100Hz~200KHz;测量精度≤±0.2%,周期精度≤±0.2%。
3. 实现信号占空比测量,被测信号占空比范围为:20%~90%,测量误差≤10%。
4. 采用LCD对测量结果进行展示
二、方案设计
1.设计前准备
用到的软件有CubeMX和CubeIDE,这两个软件都是由ST公司为了方便编写代码配套的软件,可以在CubeMX中配置好引脚和时钟树等,然后直接生成初始化代码,在生成的代码中只要自己添加启动代码(一定要注意,我当时因为这个找了半天的原因!!!)和回调函数代码即可。具体软件可以在官网上或者其他快速途径下载(我是在ST官网上下载的)。
2.硬件设计
因为STM32的参考电压是3.3V,所以能最后得到的电压最高就是3.3V,并不能达到题目的要求,所以我们要加硬件电路来确保我们能测到5V。
方案一:对5V待测量增加一个线性放大前级模组来等比例缩小信号,比如增加一个放大率为0.5的,这样信号的最大量就变成2.5V,后面ADC后使用值时再直接乘以2来使用。
方案二:也可以简单点用两个精密大电阻来分压测量。
因为在实验室环境下,方案一更容易实现,我在这里选择了方案一。
3、软件设计
1、幅值测量
STM32的ADC是12位,读到的ADC值是从0到4095(111111111111)。当把ADC引脚接了GND,读到的就是0;当把ADC引脚接了VDD,读到的就是4095。这是一个线性表达,但是你这时候读出来怎么到时是多少呢?在芯片出场的时候就会给芯片设一个参考电压(STM32G474的参考电压是3.3V),这时候我们就知道如何读出准确值了:实际电压=(ADC值x3.3)/4095
利用STM32芯片中的ADC模块捕捉有效ADC值,利用两个if语句找出最大值和最小值,最大值减最小值就是要求的幅值。为了结果精确可以加个求取平均值的函数(也有用中断方式实时显示电压值的,但是没有很理解所以采用了上面简单的方式)。代码如下:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* ADC1_Handler){
adc_value = HAL_ADC_GetValue(ADC1_Handler);
if(adc_value > adc_max) adc_max = adc_value;
if(adc_value < adc_min) adc_min = adc_value;
if(adc_max == adc_min) adc_voltage = 0;
adc_voltage = adc_max - adc_min;
adc_value_100 = (adc_voltage*330)/4095;
adc_value_b = adc_value_10/100;
adc_value_s = (adc_value_10%100)/10;
adc_value_g = adc_value_10%100;
HAL_ADC_Stop_IT(&hadc1);
}
其中因为除了4095的原因,我将adc_voltage的值乘100,再分个十百分别读出。
然后对于我这样的一个小白不出意外的话意外就发生了,读出的值差不多是测量的值的两倍,翻阅资料后可以得知是因为信号源的阻抗和负载阻抗的不匹配,导致了电压基本上都分给了负载,解决方法是将信号源改成高阻抗输出。
2、频率测量
运用STM32中输入捕获模块,原理图如下。
如图所示,测量采用的是不复位的输入捕获,在第一个上升沿的时候开启TIM2_CHANNEL1(上升沿捕获)和TIM2_CHANNNEL2(下降沿捕获),状态数置1,在接下来的下降沿时候将捕获放入CCR2寄存器中,上升沿时将捕获放入CCR1寄存器中,最终的周期就是两段上升沿中间的时间,频率则是周期的倒数,占空比是高电平时间(存在CCR2中)与周期的比值。
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(TIM2==htim->Instance)
{
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1 )
{
if(capture_Cnt == 0)
{
//capture_Buf[0] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
assert_param(IS_TIM_CC1_INSTANCE(htim2->Instance));
capture_Buf[0] = htim->Instance->CCR1;
capture_Buf1[0] = htim->Instance->CCR2;
capture_Cnt = 1;
}
else if(capture_Cnt == 1)
{
// capture_Buf[2] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
assert_param(IS_TIM_CC1_INSTANCE(htim2->Instance));
capture_Buf[2] = htim->Instance->CCR1;
capture_Buf1[2] = htim->Instance->CCR2;
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); //启动频率捕获
capture_Cnt = 0;
}
}
}
}
因为当测到高频率的时候,刷新速度很快,所以在写回调函数的时候应该尽量内容少些。当时接入频率的管教时,显示屏一片空白,将代码搬出去后情况好多了。
3、按键切换
配置uart端口,利用TIM6来刷新界面。然后利用变量state来表明自己切换在哪个界面,在实
验中利用state%2来表示1和0两个状态,当1状态时显示幅值界面,0状态时显示频率界面。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//基本定时器回调函�??????
{
if(htim->Instance == TIM6){//TIM6负责按键�??????????测与lcd显示,以�??????????个低的频率执行,减少cpu的负�??????????
// if(states == 1)lcd_show_string(72, 168, 24, "V:%d.%d%d",adc_value_b,adc_value_s,adc_value_g);//上部显示
k3 = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3);
k4 = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_4);
if(k3 == 0) {
HAL_UART_Transmit(&hlpuart1, "K3\n", 3, 2000);
if(states == 1){
// if(para_R>0)para_R = para_R-2;
lcd_clear(BLACK);
lcd_set_color(BLACK,WHITE);
lcd_show_string(72, 32, 24, "Voltage:");//上部显示
lcd_show_string(72, 32*2, 24, "adc_max:%d",adc_max);
lcd_show_string(72, 32*4, 24, "V:%d.%d%d",adc_value_b,adc_value_s,adc_value_g);//上部显示
}
}
if(k4 == 0){
HAL_UART_Transmit(&hlpuart1, "K4\n", 3, 2000);
states++;
states = states%2;
if(states == 0){
lcd_clear(BLACK);
lcd_set_color(BLACK,WHITE);
capture_Buf[3] = (capture_Buf[2] - capture_Buf[0]);
capture_Buf1[3] = (capture_Buf1[2] - capture_Buf[0]);
frequency = HAL_RCC_GetPCLK2Freq() / capture_Buf[3];
duty_cycle=capture_Buf1[3]*100/capture_Buf[3];
period = 1/frequency;
lcd_show_string(72, 32, 24, "Frequency");//上部显示
lcd_show_string(72, 32*2, 24, "FRQ:%d",frequency);//上部显示
sprintf(text,"duty:%f",duty_cycle);
// sprintf(text1,"period:%f",period);
// lcd_show_string(40, 32*3, 24, text1 );
lcd_show_string(40, 32*4, 24, text );//上部显示
}
else{
lcd_clear(BLACK);
lcd_set_color(BLACK,WHITE);
lcd_show_string(72, 32, 24, "Voltage:");//上部显示
lcd_show_string(72, 32*2, 24, "adc_max:%d",adc_max);
lcd_show_string(72, 32*3, 24, "V:%d.%d%d",adc_value_b,adc_value_s,adc_value_g);//上部显示
}
}
}
}
这里面就涉及到一个问题,我频率能正确的输出,但是周期和占空比怎么调都是0,后来找到一种办法就是在前面添加头文件“stido.h”,然后后面用sprintf函数将值打印成字符串。然后再用显示函数将它打印出来。如果有哪位大佬能帮我分析一下原因我会很高兴。
4、屏幕显示
配置SPI端口,利用LCD_show_string函数显示需要的内容
5、端口总配置
总结
这次电子设计3让我认识到了我自己的许多不足,之前有很多机会都可以让我熟悉STM32,但是都没有把握住,这次设计是个很好的机会。在第一周的时间,我四处查资料,想学习STM32的使用和测幅值频率等等的方法。最后方案逐渐成型,在第二周我准备着手配置管脚和写代码。第三周本来想花点时间将拓展部分弄一下,最后因为提前放假没有时间。希望大家能好好学习,不至于像我这样焦头烂额的,有不懂的可以在评论区留言。
边栏推荐
- The difference and connection between dist, pdist and pdist2 in MATLAB
- DOM - page rendering process
- tab 替换空格
- Scala的模式匹配与样例类
- Nvm,Nrm使用教程
- 炎炎夏日打造一个属于自己的“便携小空调”吧
- 解决启动filebeat时遇到Exiting: error unpacking config data: more than one namespace configured accessing错误
- MYSQL5.7详细安装步骤
- 网络运维系列:端口占用、端口开启检测
- 华为Mux VLAN 二层流量隔离
猜你喜欢
随机推荐
golang八股文整理(持续搬运)
The DOM event type
(三)文件操作之一——文件IO
在命令行或者pycharm安装库时出现:ModuleNotFoundError: No module named ‘pip‘ 解决方法
二、QT界面开发--新建C语言工程
网络运维系列:Ubnt ER-X初始化和开启硬件NAT
解决启动filebeat时遇到Exiting: error unpacking config data: more than one namespace configured accessing错误
Mysql索引优化二
【频域分析】频谱泄露、频率分辨率、栅栏效应
【无标题】
lammps聚合物建模——EMC
Mysql删库恢复数据
Redis6
JVM常量池详解
对象头和synchronized的升级
网络运维系列:网络出口IP地址查询
Servlet 技术1
nodejs 的下载安装与环境配置
【Hiflow】 开辟新道路的自动化助手!
Golang学习(三十五) go 连接redis