Qt调用工业相机之巴斯勒相机

article/2025/11/7 11:12:51

作者:billy
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

开发环境

操作系统:Windows 10 1903 18362.778
相机型号:BASLER acA 1300-60gm
相机软件:pylon_Runtime_6.0.0.17906,Basler_pylon_5.0.10.10613
软件版本:Qt 5.12.8, vs2017 Community
通信方式:GigE - 千兆以太网通信协议

驱动与SDK

开发包和驱动下载地址
提取码:lg0i

驱动安装完成之后需要完成一些配置才能成功连接相机

  1. 将相机通电,使用网线将相机与电脑连接。确保相机与电脑处于连接状态。可以观察网
    络连接中,本地连接的状态;
  2. 网络连接中,右键本地连接,选择属性。在属性界面中点击”配置”按钮,进入”高级”选项卡,设置 Jumbo Packet (巨型帧)为当前可设置的最大值。点击确定保存参数;
    在这里插入图片描述
    在这里插入图片描述
  3. 在网络连接中,右键”本地连接”,双击 “Internet 协议版本 4”,在弹出界面中勾选 “自动获得 IP 地址”
    ,点击确定保存参数;
    在这里插入图片描述
    在这里插入图片描述
  4. 打开 “Pylon IP Configurator”工具,在列表中选择当前连接的相机。选择相机后,选择 “DHCP”,点击保存。”Refresh” 确保相机的 “Status” 为 ”OK”,并且界面右下角没有警告;
    在这里插入图片描述

安装驱动和开发包完成之后,可以找到以下目录:

  1. C:\Program Files\Basler\pylon 5
    在这里插入图片描述
  • Applications - 应用程序 pylon Viewer 和 pylon IP Configurator;
  • Development - 开发文档、头文件、库文件、示例程序源代码等等;
  • License - 开发许可证;
  • Runtime - 运行时需要的依赖库(打包程序时需要包含);
  • Release Notes.txt - 发行笔记;

巴斯勒相机介绍

巴斯勒相机实时获取图像的原理就是对每一帧数据的处理,即 拍照 - 处理数据 - 拍照 - 处理数据 …
SDK中提供了两种方式来处理图像,我们先来看一下最主要的开始抓取图像的函数 StartGrabbing:
virtual void StartGrabbing( EGrabStrategy strategy = GrabStrategy_OneByOne,
EGrabLoop grabLoopType = GrabLoop_ProvidedByUser);

来看一下函数的两个参数代表什么含义

  • One by One Grab Strategy
    这种模式是最简单的,也是 CInstantCamera 默认的图像获取策略。
    获取到的图像放到一个FIFO 队列中。每次我们从队列中取的(RetrieveResult)都是最早放到队列中的图像

  • Latest Image Only Grab Strategy
    这个策略下只有最新到的图像保存在输出队列中。
    如果一份旧图像还没被读取新图像就又来了,那么旧图像就被舍弃。这样可以保证读取到图像永远都是读取时刻最新的。

  • Latest Images Grab Strategy
    这个模式下输出队列可以保存不止一张图像,具体最多能保存几张图象由 CInstantCamera::OutputQueueSize 来指定。
    当新的图像来了,而队列已满时,旧的图像被舍弃。
    当 CInstantCamera::OutputQueueSize 为 1 时就是 Latest Image Only Grab Strategy。
    当 CInstantCamera::OutputQueueSize = CInstantCamera::MaxNumBuffer,就和 One by One Grab Strategy 一样了。

  • Upcoming Image Grab Strategy
    这个模式很特别,只有当 CInstantCamera::RetrieveResult() 被调用后才会采集图像。USB 相机不支持这种策略。

  • GrabLoop_ProvidedByUser
    用户在代码中循环调用RetrieveResult() 来处理抓取的图像和相机事件。默认使用这种模式

  • GrabLoop_ProvidedByInstantCamera
    抓取循环线程由即时相机提供。它会不断循环调用RetrieveResult()。抓取的图像由注册的图像事件处理程序处理。抓取循环线程在抓取启动时启动

StartGrabbing的第一个参数代表获取图像的策略,第二个参数代表的是使用哪个循环线程来抓取图像。由第二个参数我们就可以分两种方式来处理图像数据:

  1. 用户自己处理,步骤如下:
  • 调用 StartGrabbing 开始抓取图像
    m_baslerCamera.StartGrabbing(GrabStrategy_OneByOne, GrabLoop_ProvidedByUser);
  • 用户自己循环调用 RetrieveResult
    m_baslerCamera.RetrieveResult(1000, ptrGrabResult, TimeoutHandling_ThrowException);
  • 处理数据 ptrGrabResult
    CImagePersistence::Save(ImageFileFormat_Bmp, filename, ptrGrabResult);
  1. 使用相机的循化线程,步骤如下:
  • 注册图像事件处理程序
    m_baslerCamera.RegisterImageEventHandler(this, RegistrationMode_Append, Cleanup_Delete);
  • 重写图像处理函数 OnImageGrabbed
    virtual void OnImageGrabbed(CInstantCamera &camera, const CGrabResultPtr &grabResult) override;
  • 调用 StartGrabbing 开始抓取图像
    m_baslerCamera.StartGrabbing(GrabStrategy_OneByOne, GrabLoop_ProvidedByInstantCamera);
  • 注意事项:相机获取到图像就会调用回调函数 OnImageGrabbed,图像处理是在不同的线程所以需要加锁

我的代码

实现功能:相机图像的实时显示,并且可以在需要的时候获取当前帧数据,用于分析或者保存;

首先需要在pro中配置头文件和库文件

INCLUDEPATH += $$PWD/include/ \$$PWD/include/pylonwindows {contains(DEFINES, WIN64) {LIBS += -L$$PWD/lib/x64/ -lGCBase_MD_VC120_v3_0_Basler_pylon_v5_0LIBS += -L$$PWD/lib/x64/ -lGenApi_MD_VC120_v3_0_Basler_pylon_v5_0LIBS += -L$$PWD/lib/x64/ -lPylonBase_MD_VC120_v5_0LIBS += -L$$PWD/lib/x64/ -lPylonC_MD_VC120LIBS += -L$$PWD/lib/x64/ -lPylonGUI_MD_VC120_v5_0LIBS += -L$$PWD/lib/x64/ -lPylonUtility_MD_VC120_v5_0} else {LIBS += -L$$PWD/lib/Win32/ -lGCBase_MD_VC120_v3_0_Basler_pylon_v5_0LIBS += -L$$PWD/lib/Win32/ -lGenApi_MD_VC120_v3_0_Basler_pylon_v5_0LIBS += -L$$PWD/lib/Win32/ -lPylonBase_MD_VC120_v5_0LIBS += -L$$PWD/lib/Win32/ -lPylonC_MD_VC120LIBS += -L$$PWD/lib/Win32/ -lPylonGUI_MD_VC120_v5_0LIBS += -L$$PWD/lib/Win32/ -lPylonUtility_MD_VC120_v5_0}
}

自定义相机基类 Camera

#ifndef CAMERA_H
#define CAMERA_H#include <QObject>
#include <QImage>
#include <QTimer>
#include <QMutex>#include <opencv2/opencv.hpp>class Camera : public QObject
{Q_OBJECTpublic:enum CameraType {Basler = 1,                     // 巴斯勒相机IC_Imaging,                     // 映美精相机MV,                             // 海康威视相机Virtual                         // 虚拟相机};explicit Camera(CameraType type = Basler) : m_type(type) {}virtual void initCamera() = 0;      // 初始化相机virtual void destroyCamera() = 0;   // 销毁相机virtual void openCamera() = 0;      // 打开相机virtual void closeCamera() = 0;     // 关闭相机virtual void startWork() = 0;       // 开始工作virtual void stopWork() = 0;        // 停止工作virtual cv::Mat takeAPic() = 0;     // 获取当前图像void start() { m_timer.start(); }void stop() { m_timer.stop(); }void setInterval(int time) { m_timer.setInterval(time); }CameraType getCameraType() { return m_type; }signals:void updateImage(QImage image);protected:CameraType m_type;QMutex m_mutex;QTimer m_timer;
};#endif // CAMERA_H

自定义 BBaslerCamerControl 相机控制类

#ifndef BBASLERCAMERCONTROL_H
#define BBASLERCAMERCONTROL_H#include "../camera.h"
#include "PylonIncludes.h"using namespace std;
using namespace Pylon;
using namespace GenApi;class BBaslerCamerControl : public Camera
{Q_OBJECT
public:enum BaslerCameraProperty {DeviceModelName,            // 相机名称DeviceID,                   // 相机SN号ResultingFrameRateAbs,      // 相机帧率AcquisitionFrameRateAbs,    // 相机频率Freerun,                    // 相机内触发Line1,                      // 相机外触发ExposureTimeAbs,            // 相机曝光时间GainRaw,                    // 相机增益SensorWidth,                // 传感器宽度SensorHeight,               // 传感器高度Width,                      // 图片宽度Height,                     // 图片高度PixelFormat,                // 图片的格式};explicit BBaslerCamerControl(Camera::CameraType type = Camera::CameraType::Basler);virtual void initCamera() override;virtual void destroyCamera() override;virtual void openCamera() override;virtual void closeCamera() override;virtual void startWork() override;virtual void stopWork() override;virtual cv::Mat takeAPic() override;QString getCameraProperty(BBaslerCamerControl::BaslerCameraProperty type);                  // 获取相机参数void setCameraProperty(BBaslerCamerControl::BaslerCameraProperty type, double value = 0.0); // 设置相机参数public slots:void updateFrame();private:CInstantCamera m_baslerCamera;  // 实例化相机对象INodeMap *m_nodeMap;            // 相机属性节点QString m_currentMode;          // 相机触发模式
};#endif // BBASLERCAMERCONTROL_H
#include "bbaslercamercontrol.h"
#include "globalfun.h"BBaslerCamerControl::BBaslerCamerControl(Camera::CameraType type) : Camera(type)
{m_timer.setInterval(GlobalValue::cam_itl);connect(&m_timer, &QTimer::timeout, this, &BBaslerCamerControl::updateFrame);
}void BBaslerCamerControl::initCamera()
{try {Pylon::PylonInitialize();   // 调用其他 pylon 函数之前必须调用 PylonInitialize 完成初始化} catch (GenICam::GenericException &e) {qDebug() << "initCamera error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::destroyCamera()
{try {stopWork();closeCamera();Pylon::PylonTerminate();    // 释放 pylon 运行时系统分配的资源} catch (GenICam::GenericException &e) {qDebug() << "destroyCamera error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::openCamera()
{try {m_baslerCamera.Attach(CTlFactory::GetInstance().CreateFirstDevice());   //实例化找到的第一个相机m_baslerCamera.Open();      // 打开相机m_nodeMap = &m_baslerCamera.GetNodeMap();   // 获取相机属性节点m_currentMode = getCameraProperty(Line1);   // 获取相机触发模式} catch (GenICam::GenericException &e) {qDebug() << "openCamera error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::closeCamera()
{try {if ( m_baslerCamera.IsOpen() ) {m_baslerCamera.DetachDevice();  // 分离连接的 pylon 设备m_baslerCamera.Close();         // 关闭连接的 pylon 设备m_nodeMap = nullptr;            // 相机属性节点置空m_currentMode = "";             // 相机触发模式置空}} catch (GenICam::GenericException &e) {qDebug() << "closeCamera error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::startWork()
{// Check if camera is open.if ( !m_baslerCamera.IsOpen() ) {return;}try {m_baslerCamera.StartGrabbing(GrabStrategy_LatestImageOnly, GrabLoop_ProvidedByUser);  // 开始抓取图像m_timer.start();} catch (GenICam::GenericException &e) {qDebug() << "startWork error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::stopWork()
{try {if ( m_baslerCamera.IsGrabbing() ) {m_baslerCamera.StopGrabbing();  // 停止抓取图像m_timer.stop();}} catch (GenICam::GenericException &e) {qDebug() << "stopWork error: " + QString::fromLocal8Bit(e.what());}
}cv::Mat BBaslerCamerControl::takeAPic()
{// Check if camera is open.if ( !m_baslerCamera.IsOpen() ) {return cv::Mat();}QMutexLocker locker(&m_mutex);try {CGrabResultPtr ptrGrabResult;m_baslerCamera.RetrieveResult(1000, ptrGrabResult, TimeoutHandling_ThrowException);if ( ptrGrabResult->GrabSucceeded() ) {CPylonImage pylogimage;CImageFormatConverter formatconverter;formatconverter.OutputPixelFormat = PixelType_RGB8packed;formatconverter.Convert(pylogimage, ptrGrabResult);cv::Mat mat = cv::Mat(int( ptrGrabResult->GetHeight() ),int( ptrGrabResult->GetWidth() ),CV_8UC3,static_cast< uchar* >( pylogimage.GetBuffer() ));return mat.clone();} else {return cv::Mat();}} catch (GenICam::GenericException &e) {qDebug() << "takeAPic error: " + QString::fromLocal8Bit(e.what());return cv::Mat();}
}QString BBaslerCamerControl::getCameraProperty(BBaslerCamerControl::BaslerCameraProperty type)
{// Check if camera is open.if ( !m_baslerCamera.IsOpen() ) {return "";}QString ret = "";try {switch (type) {case DeviceModelName: {const CStringPtr deviceModelName = m_nodeMap->GetNode("DeviceModelName");ret = QString::fromLocal8Bit(deviceModelName->ToString().c_str());} break;case DeviceID: {const CStringPtr deviceID = m_nodeMap->GetNode("DeviceID");ret = QString::fromLocal8Bit(deviceID->ToString().c_str());} break;case ResultingFrameRateAbs: {const CFloatPtr resultingFrameRateAbs = m_nodeMap->GetNode("ResultingFrameRateAbs");ret = QString::number(resultingFrameRateAbs->GetValue());} break;case AcquisitionFrameRateAbs: {const CBooleanPtr acquisitionFrameRateEnable = m_nodeMap->GetNode("AcquisitionFrameRateEnable");acquisitionFrameRateEnable->SetValue(TRUE);const CFloatPtr acquisitionFrameRateAbs = m_nodeMap->GetNode("AcquisitionFrameRateAbs");ret = QString::number(acquisitionFrameRateAbs->GetValue());} break;case Freerun:case Line1: {const CEnumerationPtr triggerSelector = m_nodeMap->GetNode("TriggerSelector");triggerSelector->FromString("FrameStart");CEnumerationPtr triggerSource = m_nodeMap->GetNode("TriggerSource");ret = QString::fromLocal8Bit(triggerSource->ToString().c_str());} break;case ExposureTimeAbs: {const CFloatPtr exposureTimeAbs = m_nodeMap->GetNode("ExposureTimeAbs");ret = QString::number(exposureTimeAbs->GetValue());} break;case GainRaw: {const CIntegerPtr gainRaw = m_nodeMap->GetNode("GainRaw");ret = QString::number(gainRaw->GetValue());} break;case SensorWidth: {const CIntegerPtr sensorWidth = m_nodeMap->GetNode("SensorWidth");ret = QString::number(sensorWidth->GetValue());} break;case SensorHeight: {const CIntegerPtr sensorHeight = m_nodeMap->GetNode("SensorHeight");ret = QString::number(sensorHeight->GetValue());} break;case Width: {const CIntegerPtr width = m_nodeMap->GetNode("Width");ret = QString::number(width->GetValue());} break;case Height: {const CIntegerPtr height = m_nodeMap->GetNode("Height");ret = QString::number(height->GetValue());} break;case PixelFormat: {const CEnumerationPtr pixelFormat = m_nodeMap->GetNode("PixelFormat");ret = QString::fromLocal8Bit(pixelFormat->ToString().c_str());} break;default: ret = ""; break;}} catch (GenICam::GenericException &e) {qDebug() << "getCameraProperty error: " + QString::fromLocal8Bit(e.what());}return ret;
}void BBaslerCamerControl::setCameraProperty(BBaslerCamerControl::BaslerCameraProperty type, double value)
{// Check if camera is open.if ( !m_baslerCamera.IsOpen() ) {return;}try {switch (type) {case AcquisitionFrameRateAbs: {const CBooleanPtr acquisitionFrameRateEnable = m_nodeMap->GetNode("AcquisitionFrameRateEnable");acquisitionFrameRateEnable->SetValue(TRUE);const CFloatPtr acquisitionFrameRateAbs = m_nodeMap->GetNode("AcquisitionFrameRateAbs");acquisitionFrameRateAbs->SetValue(value);} break;case Freerun: {CEnumerationPtr triggerSelector = m_nodeMap->GetNode("TriggerSelector");triggerSelector->FromString("FrameStart");CEnumerationPtr triggerMode = m_nodeMap->GetNode("TriggerMode");triggerMode->SetIntValue(1);CEnumerationPtr triggerSource = m_nodeMap->GetNode("TriggerSource");triggerSource->FromString("Software");} break;case Line1: {CEnumerationPtr triggerSelector = m_nodeMap->GetNode("TriggerSelector");triggerSelector->FromString("FrameStart");CEnumerationPtr triggerMode = m_nodeMap->GetNode("TriggerMode");triggerMode->SetIntValue(1);CEnumerationPtr triggerSource = m_nodeMap->GetNode("TriggerSource");triggerSource->FromString("Line1");} break;case ExposureTimeAbs: {const CFloatPtr exposureTimeAbs = m_nodeMap->GetNode("ExposureTimeAbs");exposureTimeAbs->SetValue(value);} break;case GainRaw: {const CIntegerPtr gainRaw = m_nodeMap->GetNode("GainRaw");gainRaw->SetValue(value);} break;case Width: {const CIntegerPtr width = m_nodeMap->GetNode("Width");width->SetValue(value);} break;case Height: {const CIntegerPtr height = m_nodeMap->GetNode("Height");height->SetValue(value);} break;default: break;}} catch (GenICam::GenericException &e) {qDebug() << "setCameraProperty error: " + QString::fromLocal8Bit(e.what());}
}void BBaslerCamerControl::updateFrame()
{QMutexLocker locker(&m_mutex);try {CGrabResultPtr ptrGrabResult;m_baslerCamera.RetrieveResult(1000, ptrGrabResult, TimeoutHandling_ThrowException);if ( ptrGrabResult->GrabSucceeded() ) {CPylonImage pylogimage;CImageFormatConverter formatconverter;formatconverter.OutputPixelFormat = PixelType_RGB8packed;formatconverter.Convert(pylogimage, ptrGrabResult);cv::Mat mat = cv::Mat(int( ptrGrabResult->GetHeight() ),int( ptrGrabResult->GetWidth() ),CV_8UC3,static_cast< uchar* >( pylogimage.GetBuffer() ));QImage image((const unsigned char *)(mat.data), mat.cols, mat.rows, mat.cols * 3, QImage::Format_RGB888);emit updateImage(image.rgbSwapped());}} catch (GenICam::GenericException &e) {qDebug() << "updateFrame error: " + QString::fromLocal8Bit(e.what());}
}

其他请参考

  • Qt调用工业相机之映美精相机
  • Qt调用工业相机之海康威视相机

http://chatgpt.dhexx.cn/article/f1XULtdP.shtml

相关文章

W25QXX使用教程

W25QXX是华邦公司生产的一块FLASH储存芯片 那W25Q256为例&#xff1a;驱动方式&#xff1a;单路双路四路SPI、QSPI&#xff1b; 擦写周期&#xff1a;10W次 支持电压&#xff1a;2.7~3.6V 频率&#xff1a;单路最大104Mhz、双路208Mhz、四路416Mhz 容量&#xff1a;容量为32M字…

flash spi w25q128 w25q64 w25q32 w25q16 verilog fpga程序代码

flash spi w25q128 w25q64 w25q32 w25q16 verilog fpga程序代码 fpga w25q128/64/32/16 verilog代码 资料包清单&#xff1a; 1.w25qxx_code_uart_top&#xff1a;altera工程代码&#xff0c;可移植ise&#xff0c;后续会出&#xff0c;需要的话提前加好友 2.功能说明书 注1&a…

STM32读写W25Q

文章目录 硬件外观引脚说明代码摘要代码获取 硬件外观 引脚说明 关于如何接线&#xff1f; 1&#xff0c;CS 2&#xff0c;MISO 3&#xff0c;3.3V 4&#xff0c;GND 5&#xff0c;MOSI 6&#xff0c;SCK 7&#xff0c;3.3V 8&#xff0c;3.3V 关于如何查询芯片引脚&#xff…

SPI Flash芯片W25Q32英文版数据手册解读(三)---------程序编写,电路应用

一、序言 序言对这篇文章进行一个总体的说明&#xff1a; 1、这部分是根据手册写程序&#xff0c;因此采用手册截图程序截图的形式&#xff0c;对图片不进行标号&#xff0c;而且对重点部分进行颜色标注。 2、考虑到很多读者&#xff08;包括我&#xff09;&#xff0c;使用…

K_A39_012 基于STM32驱动W25Q32 模块读写数据 串口+OLED0.96显示

K_A39_012 基于STM32驱动W25Q32 模块读写数据 串口OLED0.96显示 所有资源导航一、资源说明二、基本参数参数引脚说明 三、驱动说明时序对应程序: 四、部分代码说明1、接线引脚定义1.2、STM32F103C8T6W25Q32 模块 五、基础知识学习与相关资料下载六、视频效果展示与程序资料获取…

W25Q16编址详解

W25Q16是一款基于SPI接口Flash存储器。 但往往我们对一串长长的16进制地址无从下手&#xff0c;以至于数据存储位置不当。 先看一下官方的数据手册 看着比较乱&#xff0c;我们自己画一个思维导图帮助理解 可以看到W25Q16最大寻址范围为0x000000H~0x1FFFFFH &#xff0c;根据…

rt-thread通过spi连接W25Q32后无法读取ID

注意&#xff0c;cs引脚必须由rtt控制&#xff0c;但是我这个cs引脚用的是PA15&#xff0c;它默认是jlink的引脚&#xff0c;所以首先要将jlink禁用&#xff0c;如下&#xff1a; rcu_periph_clock_enable(RCU_AF);rcu_periph_clock_enable(RCU_GPIOA);rcu_periph_clock_enable…

stm32 操作W25Q256 W25Q16 spi flash

硬件连接 今天我使用W25Q16做了一个测试&#xff0c;发现了W25Q16内部是一个环形缓冲区&#xff0c;在0x200000地址处写入数据&#xff0c;我可以在0x000000处读取到0x200000地址的数据&#xff0c;从这里就可以正面W25Q16是一个环形缓冲区的norfalsh 本函数库来自正点原子官…

W25Q32的使用

一、W25Q32简介 W25Q32是华邦公司推出的大容量“SPI FLASH” 产品。 1、容量 32M-Bit/4M-byte(4,194,304)2、存储结构 页:256-bytes扇区:4K-bytes块:64K_bytes是故: 页:16384个扇区:1024个块:64个3、速度 时钟速度最高:80MHz4、特性 擦除、写次数:高达100,000次数据保…

基于STM32实现W25Q16读写操作(spi)

文章目录 前言一、W25Q161.介绍2.SPI2.1. 简介2.2. 特性2.3. 功能说明2.4. 工作模式2.5. 引脚说明 二、代码开发1.SPI初始化2.读取厂商ID2.1.读写字节2.2.读取ID 3.其他的一些操作4.完整代码 三、效果演示 前言 在之前我们学习了flash闪存&#xff0c;这个更多的是内部数据存储…

GD32F303访问W25Q32异常问题解决

最近在使用国产化GD32F303替换STM32F103芯片&#xff0c;驱动代码使用的STM32的库函数&#xff0c;调试过程中发现MCU通过SPI访问W25Q32芯片时&#xff0c;会出现写入异常的情况&#xff0c;不是全部错误&#xff0c;是中间某段数据错误。 左侧&#xff1a;待写入文件内容 右侧…

stm32读写w25qxx

一&#xff0c;w25qxx简介。 二&#xff0c;stm32CubeIDE配置。 三&#xff0c;代码 1,w25qxx.c #include "W25Qxx.h"/*********************************************************************************** 函数功能: 模块初始化*/ uint8_t BSP_W25Qx_Init(void) …

STM32(八)W25Q(16/32/64/128)芯片学习总结

系列文章目录 文章目录 系列文章目录前言一、硬件和数据手册部分翻译1.W25Q64硬件设计2.数据手册解读 二、指令 前言 按项目需求&#xff0c;近期调试了W25Q32芯片&#xff0c;W25Q系列芯片是华邦公司推出的大容量SPI FLASH产品&#xff0c;W25Q32是3V&#xff0c;32M-bit 串行…

STC89C52驱动W25Q32测试笔记

STC89C52是经典的C51单片机&#xff0c;该芯片不自带硬件SPI接口&#xff0c;正好有手上一块W25Q32的存储模块&#xff08;某宝上买的2.2元&#xff09;&#xff0c;试着使用89C52模拟SPI接口驱动W25Q32&#xff0c;在驱动的过程中遇到了几个问题&#xff0c;首先的问题是电平不…

SPI Flash芯片W25Q32英文版数据手册解读(二)---------存储器知识,寄存器

接着上一篇文章&#xff0c;由于W25Q32芯片是一个存储器芯片&#xff0c;先对这个芯片有关存储器的一些概念进行解读。 一、存储器相关知识 1、存储器的三个单位&#xff1a; 存储器三个等级&#xff1a;页&#xff08;Page&#xff09;&#xff0c;扇区&#xff08;sector&a…

SPI Flash芯片W25Q32英文版数据手册解读(一)---------引脚功能,工作模式

W25Q32芯片是一个可以通过SPI&#xff08;串行外围设备接口&#xff09;操作的flash存储器&#xff0c;这篇文章备忘和总结一下英文版数据手册的一些解读。有关时序及具体用STC单片机编写程序的内容等下一篇文章。 一、芯片引脚功能 我买的是8引脚、SOIC封装的芯片&#xff0…

w25q32 内存分布

说明 ESP826612F/E里面使用w25q32作为了flash存储. 提前说下哈,bit代表位 也就是 0 1 0 1 , Bit代表字节 ,一字节就是8位 w25q32的容量是32Mbit 也就是 32/8 4MB字节 4*1024 4096KB字节 然后 w25q32 这个芯片规定每 64KB字节作为一个块 所以呢w25q32总共分成了 4096…

基于STM32+SPI+W25Qxx存储芯片指令,时序和函数讲解

前言 本次我们学习一下STM32F103关于SPI对存储芯片的读写&#xff0c;介绍W25QXX芯片和对芯片内部讲解和代码解读&#xff0c;学习W25QXX芯片的各种读写指令&#xff0c;操作芯片读写&#xff0c;认识底层驱动&#xff0c;本篇内容主要目的是教会大家看手册写代码&#xf…

ButterKnife9.0.0-rc2 配置

升级了AndroidStudio到3.4之后&#xff0c;发现项目中的很多依赖库都不能用&#xff0c;原因是随着AS升级之后&#xff0c;Gradle随之升级到3.4.1&#xff0c;很多第三方库也需要更高版本的支撑&#xff0c;今天遇到ButterKnife失效的问题&#xff0c;原本是8.5.1的版本&#x…

How to install Bromine3 RC2

When I install Bromine RC2, I met bellow issues: “Server could not contact itself at the specified address: 127.0.0.1:80” “Error: Database table jobs for model job was not found.” etc. Now I show my exact way to install RC2 successfully: 1. Downl…