- 2024-11-12
-
发表了主题帖:
【L99H92直流电机驱动评估板】AEK-MOT-WINH92开发板电路分析
AEK-MOT-WINH92开发板:该电路板设计基于用于汽车应用的L99H92 H桥栅极驱动器,其特点是灵活电流传感为先进的防夹算法开发提供了不同的工具。开发板新特性:
新的防夹机制:
不利用电机编码器,而是利用电路板的三种不同类型的电流感应(串联、低侧和高侧)来实现防夹功能。
配置灵活:
可配置为与双向直流马达的单一H桥配合使用,或与两个单向直流马达的两个独立半桥配合使用。
连接便捷:
尺寸紧凑,可以轻松连接到任何微控制器。
利用单独的专用连接器进行SPI通讯、电流感应和具有故障检测功能的基本马达命令界面。
可调节增益:
用于防夹和满足任何车窗操作条件(如恶劣天气条件下打开窗户时,电流范围水平可能会发生变化)。
诊断功能:
提供三种诊断功能,用于检测设备在关闭状态时潜在的接地短路、电池短路和负载开路情况。
如果发生故障,DIAG接脚会向外部MCU发出警报。
故障安全按钮:
在电路板布局中新增了一个故障安全按钮,用于在开发阶段进行系统调试。
反极性保护:
给电路板提供强大的保护,防止因电源极性反转而造成的损坏。
高电流能力:
四个外部MOSFET允许电流高达50A,符合电路板功耗能力。
通过可编程增益电流传感实现防夹检测
•在线、低压侧和高压侧电流传感选项
•诊断引脚在发生故障时提醒微控制器,避免通过SPI进行循环按需故障检查,从而确保及时干预
•反向电池保护专用电路
•故障检测能力:
–开路负载、对地短路和对蓄电池短路情况
–热警告和超温停机
–欠压/过压保护
–过电流保护
•组件数量少
•为直流汽车应用提供L99H92 H桥栅极驱动器
•紧凑型尺寸:103毫米x80毫米
•包含在AutoDevkit生态系统中
左侧为AEK-MOT-WINH92开发板核心IC:L99H92是意法半导体(STMicroelectronics)推出的一款车规闸极驱动器,是符合AEC-Q100标准的器件。它集成了SPI端口、电荷泵及安全功能,并支持全桥与双半桥控制,适用于汽车电动系统如天窗、车窗等的直流电机控制。具有灵活的栅极驱动器,可配置电流传感,先进直流电机控制的诊断和保护功能。L99H92设计用于在单个H桥或双独立半桥配置中驱动4个外部N沟道MOSFET晶体管,用于汽车应用的直流电机控制。集成了两个可自由配置的电流感测放大器。设备具有低功耗(待机功耗),当前功耗小于5ua。可编程栅极驱动电流可以最大限度地减少EM1。每个栅极驱动器独立监测其外部MOSFET漏源电压以应对故障情况。可编程的交叉电流保护时间可以避免每个半桥的高侧和低侧激活的并发性。两个非工作状态诊断比较器检测接地短路、电池短路或开负载条件。集成标准串行外围设备接口(SPI)控制设备并提供诊断信息。额外的DIAGN输出引脚比SPI通信更快地提醒微控制设备发生故障。L99H92设备实现了诊断和保护功能,如供电电压监测、充电泵电压监测、过电流保护、温度报警和过温停机。这些器件装在TQFP32和QFN32封装中,两者都带有外露焊盘。QFN32具有可湿润的侧面,便于对焊点进行目视检查。
内部逻辑图:
工作原理:
开发板的原理图:
开发板背面有个运放:TSC103IYPT,是一款由意法生产的运算放大器及比较器,具有高共模电压范围、高共模抑制比和低输入偏置电压等特性,它通常被用于需要精确电流检测的应用中,如汽车电子、工业自动化、电源管理等。
资格:AEC-Q100
准确性:2.5%
放大器类型:High-Side Current Sense Amplifier(高边电流检测放大器)
描述/功能:High side current sense amplifier(高边电流检测放大器)
输入类型:Common Mode(共模输入)
3dB带宽:700 kHz
双重电源电压:-2.1 V to +65 V
增益V/V:20 V/V、25 V/V、50 V/V、100 V/V
转换速率(SR):0.6 V/us
AEK-MOT-WINH92是一款功能强大、配置灵活且安全可靠的车窗升降解决方案评估板。充分展示了L99H92闸极驱动器的灵活电流感应功能,其工作原理基于H桥MOSFET控制,内置了电荷泵,用于为高边驱动器供电。在车辆电池电压波动时,电荷泵能够确保驱动器运行正常,甚至在电压低至5.41V时仍能正常输出。此外,L99H92还提供了电池反接保护功能,以保护电路免受电池极性反转造成的损坏。为高级防夹算法开发提供了不同的工具。同时,其紧凑的尺寸和便捷的连接方式使得它易于集成到任何微控制器系统中。L99H92是一款功能强大、安全可靠的车规栅极驱动器,通过灵活的配置和多种安全保护功能,实现了对高电流电机的精确控制。使其在汽车系统中具有广泛的应用前景。
-
发表了主题帖:
【L99H92直流电机驱动评估板】开箱图
感谢eeworld社区和得捷给的这次测评机会,先发个开箱图:从太平洋对岸飘扬过海来的。得捷电子(Digi-Key Electronics)总部位于美国明尼苏达州锡夫里弗福尔斯市,是全球电子元器件和自动化产品高质量分销服务商。 Digi-Key 创立于 1972 年,由目录分销的开始,也是为设计工程师提供丰富资源的主要平台。
这是NUCLEO-G474RE开发板,主控STM32G4RET
这是主角:AEK-MOT-WINH92评估板的主要目标是驱动汽车直流电机车窗升降器,确保高安全水平。该板完全符合汽车市场的趋势,即车窗升降应用的演变,提供了一种新的防夹机制,无需利用电机编码器,但利用电路板三种不同类型的电流传感(在线、低压侧和高压侧)。该板可以配置为与单个H桥一起工作,以实现双向直流电机或两个独立的半桥,用于两个单向直流电机。由于其紧凑的尺寸,利用单独和专用的连接器进行SPI通信,电流传感器、感测和基本电机命令与故障检测能力接口。另一个关键特征是可调增益,用于防夹和实现任何车窗操作条件(当前范围水平可能会在以下情况下发生变化在恶劣天气条件下打开窗户(例如在结冰的情况下)。该板还提供三个诊断功能来检测潜在的对地短路,当设备处于关闭状态时。如果发生故障,DIAG引脚会向外部MCU发出警报,确保提示在开路负载、对地短路、对电池短路、热短路的情况下进行干预警告和超温停机、欠压/过压和过流保护。对于开发阶段的系统调试,有一个故障安全按钮已添加到电路板布局中。为了使电路板得到强有力的保护,并防止因电路板倒置而造成的损坏实现了电源极性、反极性保护。四个外部MOSFET允许电流高达50A,与电路板电源一致耗散帽。
- 2024-10-29
-
回复了主题帖:
测评入围名单:ST应用于车窗升降的L99H92直流电机驱动评估板,配套 NUCLEO-G474RE
可以完成任务
- 2024-01-09
-
回复了主题帖:
【DigiKey“智造万物,快乐不停”创意大赛】项目总帖:基于STM32MP157D频谱分析仪
附件为代码
-
发表了主题帖:
【DigiKey“智造万物,快乐不停”创意大赛】项目总帖:基于STM32MP157D频谱分析仪
基于STM32MP157D频谱分析仪
作者:suntongxue
前言:
随着电子通信产业的不断发展,频谱分析仪广泛运用在通信、电子、雷达及电子产品研发等领域,是电子工程师重要的频域分析工具。随着对于信号分析的不断发展,应实现频谱分析仪与上位机的通信。频谱分析仪可以通过网口、USB接口及串口向上位机发送数据,在上位机中,MATLAB、GNU radio等多种工具软件可以被用于处理该数据,扩展了频谱分析仪的功能。而且传统的频谱分析采用昂贵的FPGA (Xilinx ZYNQ)个人和小型团体均无力承受,本设计采用STM32MP157为核心实现频谱分析仪的设计与实现,STM32MP157微处理器基于的Arm® Cortex®-A7双核(工作频率800 MHz)和Cortex®-M4内核(工作频率209 MHz)架构,并配有一个专用的3D图形处理单元 (GPU),Cortex-A7 就是为了运行 Linux 这样的富操作系统,Cortex-M4可以看做一个M4内核的单片机。还需要很多部件:锁相环频率合成芯片ADF4110,压控振荡芯片MAX2606;乘法器AD835,AD835。通过STM32MP157 QT 开发人家交互GUI,实现USB或者USART实现与桌面端上位机实现高速信号通信。
系统设计概要:
一)频谱分析仪概述:
频谱分析仪是用来测量电信号频谱特征的仪器。使用频谱分析仪,可以观测到信号在频域中的分布情况、信号能量及其他频谱信息。分析仪的基础功能是以图形方式显示信号,其中 Y 轴表示幅度或功率电平,X 轴表示频率。所检测信号的幅度在频域中进行表示。射频频谱分析仪涵盖无线电和微波频率。目前,仪器可用的最大频率范围为 2 Hz 至 85 GHz,使用外部混频器时可扩展到更高频率。一般而言,X 轴的频率使用线性刻度,而 Y 轴的幅度则使用对数或分贝刻度(也属于对数刻度),这样可以同时查看幅度变化较大的信号。频谱分析仪广泛用于射频测试,不仅可以显示有用信号的属性(例如信号是否占用指定带宽),还可以搜索无用信号。射频测试几乎不再使用频谱分析仪来显示频率范围内的频谱分量,进而检测有用和无用信号的电平。许多现代脉冲信号性质各异,且需要检测和分析瞬态信号,意味着和无线电接收机采用相同的超外差原理的传统频谱分析仪无法可靠地检测所有间歇性瞬态信号,或测量信号相位。由于感兴趣的频率范围(频率跨度)超出频谱分析仪同时处理数据的能力,因此分析仪从低频到高频扫描频率跨度(扫频)。如果扫频时不存在瞬态信号,则不会检测到信号。通过快速傅里叶变换 (FTT) 从时域到频域进行数字处理,显著扩展了超外差频谱分析仪的信号检测和分析能力。FFT 能够更快地在频率跨度内捕获和分析信号:并行使用 FFT 可以提供更宽的瞬时带宽,因此可以利用合适的滤波器检测脉冲和瞬态信号。许多频谱分析仪还提供零跨度模式来分析信号的相位和幅度,并在选定的频率解调信号。除了在屏幕上简单表示检测到的信号之外,频谱分析仪还可以测量噪声、增益、相位、占用信号带宽和邻道功率。数字信号可供导出以使用软件工具进行后处理,以便提供附加分析结果。
二)系统框架:
该系统由基于锁相环的本振源、混频器、低通滤波器,频谱测量几部分组成。由PLL芯片ADF4110,VCO芯片MAX2606等组成的锁相环频率合成器产生本振信号,经过乘法器实现幅度可调后输出80~110Mhz ,幅度在10~100mV的信号。在本振信号输出后加一级10倍的固定增益放大电路,放大后的本振信号和信号源产生的被测信号经过乘法器混频后,再经过低通滤波器滤除高频分量,经过STM32MP157AD采样经过LPF的信号后根据幅值大小将信号频谱及中心频率显示在基于QT开发的GUI显示屏上。
二)系统实现:
STM32MP157 ,ADC,全称为 Analog-to-Digital Converter,即模数转换器,是一种电子电路或芯片,用于将模拟信号转换成数字信号。在模拟电路中,信号通常是以连续的形式进行表示和处理的,例如声音、温度、光强等都是模拟信号。而数字电路则是以离散的形式进行表示和处理的,例如计算机中处理的数据和图像等都是数字信号。为了将模拟信号转换成数字信号以便进行数字处理,需要使用 ADC 芯片进行转换。ADC 芯片通常由采样保持电路、模数转换电路和数字输出接口三个部分组成。采样保持电路用于对模拟信号进行采样和保持,以便进行转换;模数转换电路用于将采样信号转换成数字信号;数字输出接口则用于输出转换后的数字信号。在linux系统中,adc属于IIO(工业输入/输出)子系统。IIO(Industrial I/O)子系统是 Linux 内核中的一个框架,用于支持各种工业输入和输出设备的驱动程序。它提供了一种标准化的接口和框架,用于处理来自传感器、ADC(模数转换器)、DAC(数模转换器)和其他工业设备的数据。IIO 子系统的主要目标是为开发者提供一种统一的方法来访问各种类型的工业设备,而不必担心底层硬件的特定细节。通过 IIO 子系统,开发者可以使用一套通用的 API 和接口来读取和控制传感器数据,简化了跨不同设备的应用程序开发。IIO 子系统在 /sys/bus/iio/devices 目录下提供了一组文件,用于访问已连接的工业设备。这些文件包括设备的输入和输出接口、触发器、采样频率等信息。下面重点介绍涉及STM32MP157开发过程
1.1 ADC实现:
STM32MP157系列有2个ADC(ADC1和ADC2),每个ADC都可以独立工作,每个ADC都可以单独分配给A7或者M4内核来使用。ADC1和ADC2除了可以工作在独立模式以外,还可以在双重模式下工作(提高采样率,ADC1为主机),STM32MP157的ADC主要特性我们可以总结为以下几条:
(1)可配置16位、14位、12位、10位或8位分辨率,可通过降低分辨率来缩短转换时间,因为转换时间缩短,我们可以做到的采样率就越高。
(2)每个ADC具有多达20个的采集模拟通道,其中有6路快速通道和14路慢速通道,慢速和快速的区别主要是支持的最高采样率不同,慢速通道要比快速通道低。这些通道的A/D转换可以单次、连续、扫描或间断模式执行。
(3)ADC的结果可以左对齐或右对齐方式存储在32位数据寄存器中。
(4)ADC具有6条专用的内部通道,用于内部参考电压 (VREFINT ) 、内部温度传感器 (VSENSE )、VBAT 监测通道 (VBAT /4)、连接到DAC内部通道、VDDCORE监视通道。
(5)支持过采样,最高可以到26位采样率。
(6)每个ADC支持3路模拟看门狗。
(7)支持单独输入和差分输入。
(8)ADC输入范围:VREF– ≤ VIN ≤ VREF+。由VREF- 、VREF+ 、VDDA和VSSA 这四个外部引脚决定。把VSSA 和VREF- 接地,把 VREF+ 和VDDA接到3.3V,所以得到ADC 的输入电压范围是:0~3.3V。注意不要接超出这个范围的电压进来,否则容易烧坏芯片。
ADC采样程序设计
ADC.C
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include "adc.h"
float adc_data_float_deal(char *str)
{
float data = atof(str);
return data;
}
int adc_data_int_deal(char *str)
{
int data = atoi(str);
return data;
}
int file_data_read(char *filename, char *str)
{
int ret = 0;
FILE *data_stream = fopen(filename, "r"); /* 只读打开 */
if (data_stream == NULL)
{
printf("can't open file filename:%s\n",filename);
return -1;
}
ret = fscanf(data_stream, "%s", str);
if (!ret)
{
printf("file read error!\r\n");
}
else if (ret == EOF)
{
/* 读到文件末尾的话将文件指针重新调整到文件头 */
fseek(data_stream, 0, SEEK_SET);
}
fclose(data_stream);
return 0;
}
int adc_read(struct adc_dev *dev)
{
int ret = 0;
char str[50];
ret = file_data_read(ADC_SCALE,str);
dev->scale = adc_data_float_deal(str);
ret = file_data_read(ADC_RAW, str);
dev->raw = adc_data_int_deal(str);
dev->act = (dev->scale * dev->raw) / 1000.f;
return ret;
}
adc.h
#ifndef __ADC_H__
#define __ADC_H__
#include <stdio.h>
#define ADC_SCALE "/sys/bus/iio/devices/iio:device0/in_voltage_scale"
#define ADC_RAW "/sys/bus/iio/devices/iio:device0/in_voltage1_raw"
struct adc_dev {
int raw;
float scale;
float act;
};
/**************************************************************************
* 函数名称: ADC_open
* 函数说明:打开驱动设备文件
* 参 数:
* 返回值 : 无
*
*************************************************************************/
extern int adc_read(struct adc_dev *dev);
extern float adc_data_float_deal(char *str);
extern int adc_data_int_deal(char *str);
#endif
main.c
#include <stdio.h>
#include <unistd.h>
#include "adc.h"
int main(int argc, char const *argv[])
{
struct adc_dev adc;
int ret = 0;
while(1)
{
ret = adc_read(&adc);
if(ret == 0) {
printf("ADC 原始值:%d, 电压值:%.3fV\n", adc.raw,adc.act);
}
sleep(1);
}
return 0;
}
STM32CubeIDE设计:
STM32CubeMX的规则是先生成Kernel的dts, 然后将生成的dts文件拷贝到u-boot目录下,也就是说u-boot的设备树stm32mp157是从kernel目录拷贝过来的,所以在U-Boot阶段修改设备树,添加User code时,请同步修改kernel的设备树或者将修改好的设备树拷贝到Kernel目录,防止下次使用CubeMX生成设备树的时候,u-boot部分的修改被kernel未修改的设备树覆盖。
1.2 STM32MP157 QT实现
QT交叉开发环境实现,详细帖子另附链接。 QCustomPlot是一个用于绘图和数据可视化的Qt C++小部件。它没有进一步的依赖关系,提供友好的文档帮助。这个绘图库专注于制作好看的,出版质量的2D绘图,图形和图表,以及为实时可视化应用程序提供高性能。QCustomPlot可以导出各种格式,如矢量化的PDF文件和光栅化的图像,如PNG, JPG和BMP。QCustomPlot是用于在应用程序中显示实时数据以及为其他媒体生成高质量图的解决方案。
QtCreator配置
新建一个Qt Widgets Application工程。
界面:
逻辑程序设计:
#ifndef FFT_H
#define FFT_H
#include <QObject>
#include <QDebug>
/*
*
*
* 计算傅里叶变换频谱
*
*
* */
#define MAX_MATRIX_SIZE 4194304 // 2048 * 2048
#define PI 3.141592653
#define MAX_VECTOR_LENGTH 10000
typedef struct Complex
{
double rl; //实部 用这个当做y轴画图像就可以
double im; //虚部
}Complex;
class fft : public QObject
{
Q_OBJECT
public:
explicit fft(QObject *parent = nullptr);
// bool fft1(Complex const inVec[], int const len, Complex outVec[]);
//傅里叶转换 频域
bool fft1(QVector<Complex> inVec, int const len, QVector<Complex>&outVec);
//逆转换
bool ifft(Complex const inVec[], int const len, Complex outVec[]);
int get_computation_layers(int num);
bool is_power_of_two(int num);
void test();
signals:
public slots:
};
#endif // FFT_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPalette>
#include <algorithm>
using namespace std;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
ui(new Ui::MainWindow),
mscChanged(100)
{
ui->setupUi(this);
this->setWindowTitle("Fourier Assistant");
QIcon icon = QIcon(":/back/images/001.ico");
this->setWindowIcon(icon);
this->resize(1400, 900);
// this->setWindowState(Qt::WindowMaximized);
//背景图片
// QPalette pal;
// QPixmap pixmap(":/back/images/stop.png");
// pal.setBrush(this->backgroundRole(), QBrush(pixmap));
// this->setPalette(pal);
toolBarInit();
chartInit();
pushButtonInit();
lineEditInit();
ui->checkBoxLP->setEnabled(false);
ui->checkBoxBP->setEnabled(false);
ui->checkBoxHP->setEnabled(false);
QIntValidator *_int = new QIntValidator;
_int->setRange(0, 5000000);
ui->lineEditStart->setValidator(_int); //输入框指定输入范围
ui->lineEditEnd->setValidator(_int);
connect(&m_thread, &threadReadData::request, this, &MainWindow::showData);
connect(&progressBarTimer, &QTimer::timeout, this, &MainWindow::on_progressBar_valueChanged);
progressBarTimer.setInterval(80);
connect(&chartDataTimer, &QTimer::timeout, this, &MainWindow::handleTimeout);
chartDataTimer.setInterval(mscChanged);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::toolBarInit()
{
ui->toolBar->setMinimumSize(QSize(0,50));
ui->toolBar->setIconSize(QSize(40,40));
ui->actionOpen->setEnabled(true);
ui->actionStart->setEnabled(false);
ui->actionPause->setEnabled(false);
ui->actionStop->setEnabled(false);
ui->actionForward->setEnabled(false);
ui->actionBackward->setEnabled(false);
ui->actionThemes->setEnabled(true);
ui->actionSet->setEnabled(true);
}
//#include <QtCharts/QSplineSeries>
void MainWindow::chartInit()
{
chartSource = new Chart; //可选择数据源显示图表
chartSourceFFT = new Chart; //可选择数据源频谱
chartData = new Chart; //顺序读取显示图表
chartFFT = new Chart; //实时频谱
chartSource->m_series = new QLineSeries;
chartSourceFFT->m_series = new QLineSeries;
chartData->m_series = new QLineSeries;
chartFFT->m_series = new QLineSeries;
QPen green(Qt::red);
green.setWidth(2);
chartSource->legend()->hide();
chartSource->setCursor(QCursor(Qt::OpenHandCursor));
// chartSource->setTheme(QChart::ChartThemeBlueCerulean);
//设置坐标轴
// chartSource->m_series->setPen(green);
chartSource->m_series->setUseOpenGL(true);
chartSource->addSeries(chartSource->m_series);
chartSource->addAxis(chartSource->m_axisX, Qt::AlignBottom);
chartSource->addAxis(chartSource->m_axisY, Qt::AlignLeft);
chartSource->m_axisX->setTickCount(6);
chartSource->m_axisX->setMinorTickCount(2);
chartSource->m_axisX->setRange(0, 1000);
chartSource->m_axisY->setTickCount(4);
chartSource->m_axisY->setMinorTickCount(2);
chartSource->m_axisY->setRange(-1, 2);
// chartSource->m_axisX->setLabelsAngle(60);
chartSource->m_series->attachAxis(chartSource->m_axisX);
chartSource->m_series->attachAxis(chartSource->m_axisY);
ui->widgetSource->setRenderHint(QPainter::Antialiasing); //设置抗锯齿
ui->widgetSource->setRubberBand(QChartView::RectangleRubberBand); //设置橡皮筋(放大缩小)
ui->widgetSource->setChart(chartSource);
chartSourceFFT->legend()->hide();
chartSourceFFT->setCursor(QCursor(Qt::OpenHandCursor));
// chartSourceFFT->setTheme(QChart::ChartThemeBlueCerulean);
//设置坐标轴
chartSourceFFT->m_series->setPen(green);
chartSourceFFT->m_series->setUseOpenGL(true);
chartSourceFFT->addSeries(chartSourceFFT->m_series);
chartSourceFFT->addAxis(chartSourceFFT->m_axisX, Qt::AlignBottom);
chartSourceFFT->addAxis(chartSourceFFT->m_axisY, Qt::AlignLeft);
chartSourceFFT->m_axisX->setTickCount(4);
chartSourceFFT->m_axisX->setMinorTickCount(3);
chartSourceFFT->m_axisX->setRange(0, 512);
chartSourceFFT->m_axisY->setTickCount(5);
chartSourceFFT->m_axisY->setMinorTickCount(3);
chartSourceFFT->m_axisY->setRange(0, 0.001);
// chartData->m_axisX->setLabelsAngle(60);
chartSourceFFT->m_series->attachAxis(chartSourceFFT->m_axisX);
chartSourceFFT->m_series->attachAxis(chartSourceFFT->m_axisY);
ui->widgetSourceFFT->setRenderHint(QPainter::Antialiasing); //设置抗锯齿
ui->widgetSourceFFT->setRubberBand(QChartView::RectangleRubberBand); //设置橡皮筋(放大缩小)
ui->widgetSourceFFT->setChart(chartSourceFFT);
chartData->legend()->hide();
chartData->setCursor(QCursor(Qt::OpenHandCursor));
// chartData->setTheme(QChart::ChartThemeBlueCerulean);
//设置坐标轴
// chartData->m_series->setPen(green);
chartData->m_series->setUseOpenGL(true);
chartData->addSeries(chartData->m_series);
chartData->addAxis(chartData->m_axisX, Qt::AlignBottom);
chartData->addAxis(chartData->m_axisY, Qt::AlignLeft);
chartData->m_axisX->setTickCount(10);
chartData->m_axisX->setMinorTickCount(2);
chartData->m_axisX->setRange(0, 1000);
chartData->m_axisY->setTickCount(5);
chartData->m_axisY->setMinorTickCount(2);
chartData->m_axisY->setRange(-1, 2);
// chartData->m_axisX->setLabelsAngle(60);
chartData->m_series->attachAxis(chartData->m_axisX);
chartData->m_series->attachAxis(chartData->m_axisY);
ui->widgetData->setRenderHint(QPainter::Antialiasing); //设置抗锯齿
ui->widgetData->setRubberBand(QChartView::VerticalRubberBand); //设置橡皮筋(放大缩小)
ui->widgetData->setChart(chartData);
chartFFT->legend()->hide();
chartFFT->setCursor(QCursor(Qt::OpenHandCursor));
// chartFFT->setTheme(QChart::ChartThemeBlueCerulean);
chartFFT->setToolTip("chartFFT");
//设置坐标轴
chartFFT->m_series->setPen(green);
chartFFT->m_series->setUseOpenGL(true);
chartFFT->addSeries(chartFFT->m_series);
chartFFT->addAxis(chartFFT->m_axisX, Qt::AlignBottom);
chartFFT->addAxis(chartFFT->m_axisY, Qt::AlignLeft);
chartFFT->m_axisX->setTickCount(11);
// chartFFT->m_axisX->setMinorTickCount(2);
chartFFT->m_axisX->setRange(0, 512);
chartFFT->m_axisY->setTickCount(4);
chartFFT->m_axisY->setMinorTickCount(2);
chartFFT->m_axisY->setRange(0, 0.001);
// chartData->m_axisX->setLabelsAngle(60);
chartFFT->m_series->attachAxis(chartFFT->m_axisX);
chartFFT->m_series->attachAxis(chartFFT->m_axisY);
ui->widgetFFT->setRenderHint(QPainter::Antialiasing); //设置抗锯齿
ui->widgetFFT->setRubberBand(QChartView::VerticalRubberBand); //设置橡皮筋(放大缩小)
ui->widgetFFT->setChart(chartFFT);
}
void MainWindow::pushButtonInit()
{
ui->pushButtonSource->setEnabled(false);
QIcon icon9;
icon9.addFile(QString::fromUtf8(":/back/images/down_select.png"), QSize(), QIcon::Normal, QIcon::Off);
// ui->pushButtonSource->setIcon(icon9);
ui->pushButtonSource->setStyleSheet(
//正常状态样式
"QPushButton{"
"background-color:rgba(100,225,100,30);"//背景色(也可以设置图片)
"border-style:outset;" //边框样式(inset/outset)
"border-width:4px;" //边框宽度像素
"border-radius:10px;" //边框圆角半径像素
"border-color:rgba(255,255,255,30);" //边框颜色
"font:bold 10px;" //字体,字体大小
"color:rgba(0,0,0,100);" //字体颜色
"padding:6px;" //填衬
"outline:none;" //去掉焦点框
"}"
//鼠标按下样式
"QPushButton:pressed{"
"background-color:rgba(100,255,100,200);"
"border-color:rgba(255,255,255,30);"
"border-width:5px;" //修改边框宽度像素,目的时使按钮看起来有动态变化
"border-style:inset;"
"color:rgba(0,0,0,100);"
"}"
//鼠标悬停样式
"QPushButton:hover{"
"background-color:rgba(100,255,100,100);"
"border-color:rgba(255,255,255,200);"
"color:rgba(0,0,0,200);"
"}");
}
void MainWindow::lineEditInit()
{
ui->lineEditStart->setStyleSheet(
"QLineEdit{"
"background-color:rgba(100,225,100,0);"//背景色(也可以设置图片)
"border-style:outset;" //边框样式(inset/outset)
"border-width:4px;" //边框宽度像素
"border-radius:10px;" //边框圆角半径像素
"border-color:rgba(255,255,255,120);" //边框颜色
"font:bold 12px;" //字体,字体大小
"color:rgba(0,0,0,150);" //字体颜色
"padding:5px;" //填衬
"outline:none;" //去掉焦点框
"}");
ui->lineEditEnd->setStyleSheet(
"QLineEdit{"
"background-color:rgba(100,225,100,0);"//背景色(也可以设置图片)
"border-style:outset;" //边框样式(inset/outset)
"border-width:4px;" //边框宽度像素
"border-radius:10px;" //边框圆角半径像素
"border-color:rgba(255,255,255,120);" //边框颜色
"font:bold 12px;" //字体,字体大小
"color:rgba(0,0,0,150);" //字体颜色
"padding:5px;" //填衬
"outline:none;" //去掉焦点框
"}");
ui->lineEditLP->setStyleSheet(
"QLineEdit{"
"background-color:rgba(100,225,100,0);"//背景色(也可以设置图片)
"border-style:outset;" //边框样式(inset/outset)
"border-width:4px;" //边框宽度像素
"border-radius:10px;" //边框圆角半径像素
"border-color:rgba(255,255,255,120);" //边框颜色
"font:bold 12px;" //字体,字体大小
"color:rgba(0,0,0,150);" //字体颜色
"padding:5px;" //填衬
"outline:none;" //去掉焦点框
"}");
ui->lineEditHP->setStyleSheet(
"QLineEdit{"
"background-color:rgba(100,225,100,0);"//背景色(也可以设置图片)
"border-style:outset;" //边框样式(inset/outset)
"border-width:4px;" //边框宽度像素
"border-radius:10px;" //边框圆角半径像素
"border-color:rgba(255,255,255,120);" //边框颜色
"font:bold 12px;" //字体,字体大小
"color:rgba(0,0,0,150);" //字体颜色
"padding:5px;" //填衬
"outline:none;" //去掉焦点框
"}");
ui->lineEditLP->setText("0");
ui->lineEditHP->setText("50");
}
void MainWindow::on_actionThemes_triggered()
{
dialog = new Dialog(this); /*新建一个窗口对象,this指针指定新的窗口父对象
是MainWindow,销毁MainWindow时也会销毁子对象*/
dialog->setModal(false); //modal属性决定show()应该将弹出的dialog设置为模态还是非模态
dialog->show();
}
void MainWindow::on_actionOpen_triggered()
{
QString FileName = QFileDialog::getOpenFileName(this,
tr("文件对话框"),
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),
tr("ALL files (*);;Excel Files(*.xlsx);;Text Files(*.txt)"));
// qDebug() << "filename:" << FileName;
ui->labelPath->setText(FileName);
m_thread.filename = FileName;
if(FileName.contains(".xlsx", Qt::CaseSensitive) != true)
{
qDebug()<<"地址错误!";
QMessageBox::information(nullptr, "地址错误", "地址错误,\n请重新选择!",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
return;
}
progressBarTimer.start();
ui->actionOpen->setEnabled(false);
ui->actionStart->setEnabled(false);
ui->actionPause->setEnabled(false);
ui->actionStop->setEnabled(false);
ui->actionForward->setEnabled(false);
ui->actionBackward->setEnabled(false);
m_thread.handleFunc();
}
void MainWindow::on_actionStart_triggered()
{
ui->actionOpen->setEnabled(false);
ui->actionStart->setEnabled(false);
ui->actionPause->setEnabled(true);
ui->actionStop->setEnabled(false);
ui->actionForward->setEnabled(true);
ui->actionBackward->setEnabled(true);
chartDataTimer.start();
}
void MainWindow::on_actionStop_triggered()
{
ui->actionOpen->setEnabled(true);
ui->actionStart->setEnabled(false);
ui->actionPause->setEnabled(false);
ui->actionStop->setEnabled(false);
ui->actionForward->setEnabled(false);
ui->actionBackward->setEnabled(false);
chartData->m_series->clear();
m_buffer.clear();
chartData->zoomReset();
chartData->m_axisX->setRange(0, 1000);
chartDataCount = 0;
chartSource->m_series->clear();
m_buffer_Source.clear();
chartSource->zoomReset();
chartSource->m_axisX->setRange(0, 1000);
pauseFlag = 0;
}
void MainWindow::on_actionPause_triggered()
{
if(pauseFlag == 0)
{
chartDataTimer.stop();
ui->actionStop->setEnabled(true);
ui->actionForward->setEnabled(false);
ui->actionBackward->setEnabled(false);
pauseFlag = 1;
}else{
chartDataTimer.start();
ui->actionStop->setEnabled(false);
ui->actionForward->setEnabled(true);
ui->actionBackward->setEnabled(true);
pauseFlag = 0;
}
}
void MainWindow::on_actionBackward_triggered()
{
if(mscChanged <= 10)
ui->actionForward->setEnabled(true);
mscChanged += 10;
qDebug()<<mscChanged;
chartDataTimer.setInterval(mscChanged);
chartDataTimer.start(mscChanged);
}
void MainWindow::on_actionForward_triggered()
{
if(mscChanged >= 10)
{
mscChanged -= 5;
}else{
ui->actionForward->setEnabled(false);
}
qDebug()<<mscChanged;
chartDataTimer.setInterval(mscChanged);
chartDataTimer.start(mscChanged);
}
//void MainWindow::on_actionReset_triggered()
//{
// ui->actionOpen->setEnabled(true);
// ui->actionStart->setEnabled(false);
// ui->actionPause->setEnabled(false);
// ui->actionStop->setEnabled(false);
// ui->actionForward->setEnabled(false);
// ui->actionBackward->setEnabled(false);
// ui->actionReset->setEnabled(false);
// chartData->m_series->clear();
// m_buffer.clear();
// chartData->zoomReset();
// chartData->m_axisX->setRange(0, 1000);
// chartDataCount = 0;
// chartSource->m_series->clear();
// m_buffer_Source.clear();
// chartSource->zoomReset();
// chartSource->m_axisX->setRange(0, 1000);
// pauseFlag = 0;
//}
void MainWindow::on_actionSet_triggered()
{
chartFFT->zoomReset();
}
void MainWindow::showData(const QVariant var)
{
// QList<QList<QVariant>> excel_list;//用于将QVariant转换为Qlist的二维数组
QVariantList varRows=var.toList();
if(varRows.isEmpty())
{
QMessageBox::information(nullptr, "错误", "数据表格为空,\n请重新选择!",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
ui->actionOpen->setEnabled(true);
progressBarValue = 0;
ui->progressBar->setValue(progressBarValue);
progressBarTimer.stop();
return;
}
const int row_count = varRows.size();
qDebug()<<row_count;
ui->labelRows->setNum(row_count);
QString str = QString::number(row_count, 10);
ui->lineEditEnd->setText(str);
ui->lineEditEnd->setEnabled(false);
max_count = row_count;
QVariantList rowData;
excel_list.clear();
for(int i=0;i<row_count;++i)
{
rowData = varRows[i].toList();
excel_list.push_back(rowData);
}//转换完毕
// qDebug()<<excel_list.at(2).at(2).toDouble();
progressBarValue = 100; //数据读取完成,进度条显示100%
ui->checkBoxLP->setEnabled(true);
ui->checkBoxBP->setEnabled(true);
ui->checkBoxHP->setEnabled(true);
m_buffer.reserve(1000);
for (int i = 0; i < 1000; ++i)
m_buffer.append(QPointF(i, 0));
for(int i = 0; i < 1000; i++)
{
m_buffer[i].setY(excel_list.at(i).at(2).toDouble());
}
chartData->m_series->replace(m_buffer);
}
void MainWindow::on_progressBar_valueChanged()
{
ui->progressBar->setValue(progressBarValue);
if(progressBarValue >= 100)
{
progressBarTimer.stop();
progressBarValue = 0;
ui->actionStart->setEnabled(true);
ui->pushButtonSource->setEnabled(true);
return;
}
if(progressBarValue < 99)
{
progressBarValue += 1;
}
}
void MainWindow::on_pushButtonSource_clicked()
{
QString _valueS = ui->lineEditStart->text();
QString _valueE = ui->lineEditEnd->text();
int valueS = _valueS.toInt();
int valueE = _valueE.toInt();
if(valueE - valueS < 512 || valueE > max_count)
{
QMessageBox::information(nullptr, "输入错误", "输入范围错误,\n请重新输入!",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
return;
}
chartSource->m_series->clear();
chartSource->zoomReset();
m_buffer_Source.clear();
chartSource->m_axisX->setRange(valueS, valueE + 1);
//坐标对应,前面补零
// m_buffer_Source.reserve(valueE);
// for (int i = 0; i < valueE; i++)
// m_buffer_Source.append(QPointF(i, 0));
// for(int i = valueS; i < valueE; i++)
// {
// m_buffer_Source[i].setY(excel_list.at(i).at(2).toDouble());
// }
//坐标不对应,无补零
int count = valueE - valueS;
m_buffer_Source.reserve(count);
for (int i = valueS; i < valueE; i++)
m_buffer_Source.append(QPointF(i - valueS, 0));
for(int i = valueS; i < valueE; i++)
{
m_buffer_Source[i - valueS].setY(excel_list.at(i).at(2).toDouble());
}
chartSource->m_series->replace(m_buffer_Source);
QVector<Complex> inVec(1024);
QVector<Complex> outVec(1024);
qreal temp[512], mymax, mymin;
for(int i = valueS; i < valueS + 1024; i++)
{
inVec[i - valueS].rl = excel_list.at(i).at(2).toDouble();
}
myfft.fft1(inVec, 1024, outVec);
m_buffer_SourceFFT.reserve(512);
for (int i = 0; i < 512; i++)
m_buffer_SourceFFT.append(QPointF(i, 0));
for(int i = 0; i < 512; i++)
{
temp[i] = qAbs(outVec[i].rl);
}
mymax = *max_element(temp, temp + 512);
mymin = *min_element(temp, temp + 512);
for(int i = 0; i < 512; i++)
{
m_buffer_SourceFFT[i].setY((temp[i] - mymin) / (mymax - mymin));
}
m_buffer_SourceFFT[0].setY(0); //去除直流分量
chartSourceFFT->m_series->replace(m_buffer_SourceFFT);
m_buffer_SourceFFT.clear();
}
//void MainWindow::on_actionModel_triggered()
//{
// static int flag = 0;
// if(flag == 0)
// {
//// setWindowOpacity(0.5);设置窗口透明度
//// chartData->setBackgroundVisible(false);
//// setAttribute(Qt::WA_TranslucentBackground);
//// ui->widgetData->setStyleSheet("background: transparent");
// flag = 1;
// }else{
//// chartData->setBackgroundVisible(true);
//// setWindowOpacity(1);
// flag = 0;
// }
//}
void MainWindow::handleTimeout()
{
qreal x = chartData->plotArea().width() / chartData->m_axisX->tickCount();
m_buffer.reserve(100);
if(1000 + 100 * chartDataCount >= max_count - 100) //防止数据溢出
{
chartDataTimer.stop();
return;
}
for (int i = 1000+100*chartDataCount; i < 1000+100*(chartDataCount+1); ++i)
{
m_buffer.append(QPointF(i, 0));
}
for (int i = 1000+100*chartDataCount; i < 1000+100*(chartDataCount+1); ++i)
{
m_buffer[i].setY(excel_list.at(i).at(2).toDouble());
}
chartData->m_series->replace(m_buffer);
chartData->scroll(x, 0);
// chartDataCount++;
// QVector<Complex> inVec(1024);
// QVector<Complex> outVec(1024);
// for (int i = 0+100*chartDataCount; i < 1024+100*chartDataCount; i++)
// inVec[i-100*chartDataCount].rl = excel_list.at(i).at(2).toDouble();
// myfft.fft1(inVec, 1024, outVec);
// m_bufferFFT.reserve(512);
// for (int i = 0; i < 512; i++)
// m_bufferFFT.append(QPointF(i, 0));
// for(int i = 0; i < 512; i++)
// {
// outVec[i].rl = qAbs(outVec[i].rl);
// m_bufferFFT[i].setY(outVec[i].rl);
// }
// m_bufferFFT[0].setY(0); //去除直流分量
// chartFFT->m_series->replace(m_bufferFFT);
// m_bufferFFT.clear();
QVector<Complex> inVec(1024);
QVector<Complex> outVec(1024);
qreal temp[512], mymax, mymin;
for (int i = 0+100*chartDataCount; i < 1024+100*chartDataCount; i++)
inVec[i-100*chartDataCount].rl = excel_list.at(i).at(2).toDouble();
myfft.fft1(inVec, 1024, outVec);
m_bufferFFT.reserve(512);
for (int i = 0; i < 512; i++)
{
m_bufferFFT.append(QPointF(i, 0));
temp[i] = qAbs(outVec[i].rl);
}
mymax = *max_element(temp, temp + 512);
mymin = *min_element(temp, temp + 512);
for(int i = 0; i < 512; i++)
{
m_bufferFFT[i].setY((temp[i] - mymin) / (mymax - mymin));
}
QString _valueLP = ui->lineEditLP->text();
QString _valueHP = ui->lineEditHP->text();
int valueLP = _valueLP.toInt();
int valueHP = _valueHP.toInt();
if(ui->checkBoxLP->isChecked() == true)
{
for(int i = valueLP; i < 512; i++)
{
m_bufferFFT[i].setY(0);
}
}
if(ui->checkBoxBP->isChecked() == true)
{
for(int i = 0; i < valueLP; i++)
{
m_bufferFFT[i].setY(0);
}
for(int i = valueHP; i < 512; i++)
{
m_bufferFFT[i].setY(0);
}
}
if(ui->checkBoxHP->isChecked() == true)
{
for(int i = 0; i < valueHP; i++)
{
m_bufferFFT[i].setY(0);
}
}
m_bufferFFT[0].setY(0); //去除直流分量
chartFFT->m_series->replace(m_bufferFFT);
m_bufferFFT.clear();
chartDataCount++;
}
- 2024-01-07
-
发表了主题帖:
基于TouchGFX的表盘设计
HUAWEI WATCH GT图形用户界面是采用TouchGFX框架进行开发的,WATCH GT最大的优点是在超低功耗的条件下实现了高端的图形和流畅的动画设计,TouchGFX为嵌入式图形用户界面(GUI)提供出色的图形处理性能和流畅的动画效果,同时对资源的需求和功耗极低。TouchGFX运行在32位微控制器上实现的高端图形处理性能完全可以媲美A内核的的智能手机GUI。
先从开源地方下载一个变盘设计:
下篇介绍如何实现
- 2023-12-14
-
发表了主题帖:
【STM32MP135F-DK】在CubeMX配置STM32MP135
STM32MP135C/F设备基于高性能Arm®Cortex®-A7 32位 RISC核心工作频率高达1GHz。Cortex®-A7处理器包括一个32 Kbyte的L1指令高速缓存、32K字节的L1数据高速缓存和128K字节的二级高速缓存。Cortex®-A7处理器是一个非常节能的应用程序处理器,旨在提供丰富的高端可穿戴设备和其他低功耗嵌入式和消费类设备的性能应用程序。它提供的单线程性能比Cortex®-A5高出20%并提供与Cortex®-A9类似的性能。Cortex®-A7融合了高性能Cortex®A15的所有功能Cortex®-A17处理器,包括硬件虚拟化支持,NEON™,和128位AMBA®4 AXI总线接口。STM32MP135C/F设备提供外部SDRAM接口,支持外部高达8 GB密度(1 GB)的存储器,16位LPDDR2/LPDDR3或DDR3/DDR3L高达533MHz。STM32MP135C/F设备包含高速嵌入式存储器168 KB的内部SRAM(包括128 KB的AXI SYSRAM,两组8 KB以及一组16K字节的安全AHB SRAM和8K字节的备份SRAM域),以及连接到APB的大量增强型I/O和外围设备总线、AHB总线和支持内部和外部存储器访问。
STM32MP135虽然主频不高,但是借助ST生态工具,犹如乔峰的太极长拳也能威力无比。
下载MP1 pack.
各种资源应有尽有,
时钟树配置
只支持ST CUBE IDE,以后继续研究
STM32MP135新一代通用工业级MPU,单核Cortex-A7@1.0GHz,具有极高的性价比;支持2个千兆以太网接口、 2个CAN FD接口、 2个 USB2.0接口、8个UART接口;标准配置支持256M Nand Flash/256M DDR和4GB eMMC/512M DDR两种;这片子还是非常容易入手的。
- 2023-12-11
-
发表了主题帖:
【DigiKey“智造万物,快乐不停”创意大赛】STM32MP157D开发板系统测试
STM32MP157D-DK1 搭载ST最强MPU-STM32MP157,STM32MP157微处理器基于灵活的Arm® Cortex®-A7双核(工作频率800 MHz)和Cortex®-M4内核(工作频率209 MHz)架构,并配有一个专用的3D图形处理单元 (GPU)、一个MIPI-DSI显示接口以及一个CAN FD接口。Cortex-A7 就是为了运行 Linux 这样的富操作系统,Cortex-M4可以看做一个M4内核的单片机,类似 STM32F429,可以运行对实时性要求比较高的控制应用,也可以运行FreeRTOS、UCOS 这样的RTOS类操作系统。
[localvideo]d17ffeb3ca420bc906db964c26216d42[/localvideo]
[localvideo]88a01331fdecff99ee028c26144bf6f6[/localvideo]
[localvideo]1851f3298d93e2dab5695e665d88414d[/localvideo]
[localvideo]3894d1e291682e90376e7284b6b3ed49[/localvideo]
综上所述,ST32MP157 SOC功能强大,资源丰富,拥有各种通信接口:UART,SPI,I2C,CAN,USB,SDIO,ADC,DAC,PWM,SAI,MIPI-DSI,DVP接口,用于连接外围设备,如WLAN、Bluetooth、GPS、4G上网模块、LCD显示器和摄像头等传感器,满足不同开发者的各种需求。ST32MP157最大亮点在于引入了三个硬件加速器:ART accelerator (~动态cache) ,CCM-SRAM (~静态 cache)和数学运算加速器,可以处理物联网,工业制造体系中产生的庞大数据及分析传输工作。在工控、智能网关、医疗电子、仪器仪表、数字终端、智慧灯杆、智慧楼宇、智慧城市等领域都有不错表现。