【STM32调试(三)】采集bmp图像保存在SD卡

发布者:EternalSunset最新更新时间:2024-12-31 来源: jianshu关键字:STM32调试 手机看文章 扫描二维码
随时随地手机看文章

一、思路

这里保存的是BMP图像,需要先连接bmp图像的数据格式。在STM32上采集的数据格式是RGB565方便在LCD上显示。如果直接发送还需要处理RGB565到RGB555的格式转换,以及bmp的数据头信息。

将bmp保存在sd卡上,这里移植FATFS文件系统。

图片保存的步骤:

  • 配置bmp的图片头信息,

  • 设置数据格式掩码,

  • 写入图像数据。

二、移植文件系统

我们使用FATFS文件系统来管理SD卡,

  1. FATFS文件系统

FATFS文件系统也就是一个软件,直接去官网下载最新版本即可。官网也有基本的介绍。下图是文件系统的结构:

在这里插入图片描述


FATFS提供文件操作的API给应用层使用,完成自己的应用开发,不再需要考虑底层硬件的操作。这也是FATFS移植性好的原因。

  • 中间层:

就是FATFS文件系统连接底层和应用层的桥梁,调用底层驱动封装成文件操作的API给应用层使用。这部分不需要修改,只需要简单的修改配置文件即可。
修改共10处,修改如下(正点原子):具体看注释

ffconf.h 

//line13

#define _FS_TINY        0   /* 0:Normal or 1:Tiny */

//line20

#define _FS_READONLY    0   /* 0:Read/Write or 1:Read only */

//line36

#define _USE_STRFUNC    1   /* 0:Disable or 1-2:Enable */

//line40

#define _USE_MKFS       1   /* 0:Disable or 1:Enable */

//line44

#define _USE_FASTSEEK   1   /* 0:Disable or 1:Enable */

//line48

#define _USE_LABEL      1   /* 0:Disable or 1:Enable */

//line60

#define _CODE_PAGE  936     //采用中文GBK编码

//line92

#define _USE_LFN    3       /* 0 to 3 设置为1,支持长文件名,并采用动态内存*/

//line135

#define _VOLUMES    2

//line155

#define _MAX_SS     512

  • 底层:

底层是移植文件系统时需要我们自己根据自己的硬件平台进行编写diskio.c。我直接使用正点原子提供的代码,但是自己不写也要读懂理解啊。
这里有6个函数:

DSTATUS disk_initialize (BYTE pdrv);

DSTATUS disk_status (BYTE pdrv);

DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);

DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);

DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);

//还有一个 get_fattime 函数,只读配置可以不用写



/*-----------------------------------------------------------------------*/

/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2013        */

/*-----------------------------------------------------------------------*/

/* If a working storage control module is available, it should be        */

/* attached to the FatFs via a glue function rather than modifying it.   */

/* This is an example of glue functions to attach various exsisting      */

/* storage control module to the FatFs module with a defined API.        */

/*-----------------------------------------------------------------------*/


#include 'diskio.h'     /* FatFs lower layer API */

#include 'mmc_sd.h'

#include 'flash.h'

#include 'malloc.h'     

//   

//本程序只供学习使用,未经作者许可,不得用于其它任何用途

//ALIENTEK STM32开发板

//FATFS disio.c 驱动代码       

//正点原子@ALIENTEK

//技术论坛:www.openedv.com

//修改日期:2014/3/14

//版本:V1.0

//版权所有,盗版必究。

//Copyright(C) 广州市星翼电子科技有限公司 2009-2019

//All rights reserved                                     

// 


#define SD_CARD  0  //SD卡,卷标为0

#define EX_FLASH 1  //外部flash,卷标为1


#define FLASH_SECTOR_SIZE   512           

//对于W25Q64 

//前4.8M字节给fatfs用,4.8M字节后~4.8M+100K给用户用,4.9M以后,用于存放字库,字库占用3.09M.                     

u16     FLASH_SECTOR_COUNT= 9832;   //4.8M字节,默认为W25Q64

#define FLASH_BLOCK_SIZE    8       //每个BLOCK有8个扇区


//初始化磁盘

DSTATUS disk_initialize (

    BYTE pdrv               /* Physical drive nmuber (0..) */

)

{

    u8 res=0;       

    switch(pdrv)

    {

        case SD_CARD://SD卡

            res = SD_Initialize();//SD_Initialize() 

            if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常

            {

                SD_SPI_SpeedLow();

                SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟

                SD_SPI_SpeedHigh();

            }

            break;

        case EX_FLASH://外部flash

            SPI_Flash_Init();

            if(SPI_FLASH_TYPE==W25Q64)FLASH_SECTOR_COUNT=9832;  //W25Q64

            else FLASH_SECTOR_COUNT=0;                          //其他

            break;

        default:

            res=1; 

    }        

    if(res)return  STA_NOINIT;

    else return 0; //初始化成功

}  


//获得磁盘状态

DSTATUS disk_status (

    BYTE pdrv       /* Physical drive nmuber (0..) */

)

    return 0;


//读扇区

//drv:磁盘编号0~9

//*buff:数据接收缓冲首地址

//sector:扇区地址

//count:需要读取的扇区数

DRESULT disk_read (

    BYTE pdrv,      /* Physical drive nmuber (0..) */

    BYTE *buff,     /* Data buffer to store read data */

    DWORD sector,   /* Sector address (LBA) */

    UINT count      /* Number of sectors to read (1..128) */

)

{

    u8 res=0; 

    if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误           

    switch(pdrv)

    {

        case SD_CARD://SD卡

            res=SD_ReadDisk(buff,sector,count);  

            if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常

            {

                SD_SPI_SpeedLow();

                SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟

                SD_SPI_SpeedHigh();

            }

            break;

        case EX_FLASH://外部flash

            for(;count>0;count--)

            {

                SPI_Flash_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);

                sector++;

                buff+=FLASH_SECTOR_SIZE;

            }

            res=0;

            break;

        default:

            res=1; 

    }

   //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值

    if(res==0x00)return RES_OK;  

    else return RES_ERROR;     

}


//写扇区

//drv:磁盘编号0~9

//*buff:发送数据首地址

//sector:扇区地址

//count:需要写入的扇区数

#if _USE_WRITE

DRESULT disk_write (

    BYTE pdrv,          /* Physical drive nmuber (0..) */

    const BYTE *buff,   /* Data to be written */

    DWORD sector,       /* Sector address (LBA) */

    UINT count          /* Number of sectors to write (1..128) */

)

{

    u8 res=0;  

    if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误           

    switch(pdrv)

    {

        case SD_CARD://SD卡

            res=SD_WriteDisk((u8*)buff,sector,count);

            break;

        case EX_FLASH://外部flash

            for(;count>0;count--)

            {                                           

                SPI_Flash_Write((u8*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);

                sector++;

                buff+=FLASH_SECTOR_SIZE;

            }

            res=0;

            break;

        default:

            res=1; 

    }

    //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值

    if(res == 0x00)return RES_OK;    

    else return RES_ERROR;  

}

#endif


//其他表参数的获得

 //drv:磁盘编号0~9

 //ctrl:控制代码

 //*buff:发送/接收缓冲区指针

#if _USE_IOCTL

DRESULT disk_ioctl (

    BYTE pdrv,      /* Physical drive nmuber (0..) */

    BYTE cmd,       /* Control code */

    void *buff      /* Buffer to send/receive control data */

)

{

    DRESULT res;                                         

    if(pdrv==SD_CARD)//SD卡

    {

        switch(cmd)

        {

            case CTRL_SYNC:

                SD_CS=0;

                if(SD_WaitReady()==0)res = RES_OK; 

                else res = RES_ERROR;     

                SD_CS=1;

                break;   

            case GET_SECTOR_SIZE:

                *(WORD*)buff = 512;

                res = RES_OK;

[1] [2] [3]
关键字:STM32调试 引用地址:【STM32调试(三)】采集bmp图像保存在SD卡

上一篇:【STM32调试(一)】串口发送像素,上位机解析显示
下一篇:Archlinux下 stm32 烧写工具配置

推荐阅读最新更新时间:2026-03-25 11:24

如何使用STM32单片机实现printf打印调试信息
在写单片机程序时我们一般喜欢使用printf来通过串口打印调试信息,但这个函数是不可以直接使用的,必须做点对库函数的改动。 STM32M CUBE是ST官方提供的库以及初始化工具,很好很强大,但是在UART方面值提供了如下函数: HAL_StatusTypeDefHAL_UART_Transmit(UART_HandleTypeDef*huart,uint8_t*pData,uint16_tSize,uint32_tTimeout); HAL_StatusTypeDefHAL_UART_Receive(UART_HandleTypeDef*huart,uint8_t*pData,uint16_tSize,uint32_tT
[单片机]
STM32在线调试时,出现BP could not be set问题解决办法
程序中设置了很多断点,因为IDE变异后有的地方是打不了断点的,所以有这种提示信息,按照下图操作,将断点全部取消进行编译。编译以后再进行断点设置就可以了!
[单片机]
stm32 调试
keil armcc这编译,elf运行不正常(突然崩溃、停在HardFault_Handler (void)),照着VSM Studio改了改编译选项似乎还是不行 还是用gcc编译出elf正常 --c99 -c --cpu Cortex-M3 -D__EVAL -g -O0 --apcs=interwork --split_sections -I ...... -D__UVISION_VERSION= 518 -D_RTE_ -DUSE_HAL_DRIVER -DSTM32F103x6 -o jiaotongdeng*.o --omf_browse jiaotongdeng*.crf --depend jiaotongdeng*.
[单片机]
在家没有硬件开发板怎么调试STM32
01前言 在学习51单片机的时候,经常会使用keil+protues的方式来做一些实验,这样的模拟仿真为我们节省了很多硬件和时间成本,可以更直观的看到代码的执行过程。 那么当切换到stm32系列单片机的时候,有些版本的protues可能不支持了(有的版本也支持STM32仿真),但是keil的模拟功能还是有很大的用处,例如stm32f103单片机,在keil中可以实现很好的模拟效果。 我们可以在其中使用中断、定时器、PWM等功能,可以观测到GPIO的输出情况。然而keil对stm32系列单片机不是很好的支持,如果换一个型号,你会发现完全无法模拟!!! 02配置keil,模拟stm32系列单片机 我们可以通过修改某些地方来实现ke
[单片机]
在家没有硬件开发板怎么<font color='red'>调试</font><font color='red'>STM32</font>?
STM32硬件错误的调试技巧
在用Keil对STM32的程序进行仿真时程序有时会跑飞,停止仿真程序会停在HardFault_Handler函数里的死循环while(1)中。 这说明STM32出现了硬件错误。 硬件错误中断 STM32出现硬件错误可能有以下原因: 数组越界操作; 内存溢出,访问越界; 堆栈溢出,程序跑飞; 中断处理错误; 遇到这种情况,可以通过以下2种方式来定位到出错代码段。 方法1: 在硬件中断函数HardFault_Handler里的while(1)处打调试断点,程序执行到断点处时点击STOP停止仿真。 示例 1.2 在Keil菜单栏点击View——Registers Window,在寄存器查看窗口查找R14(LR)的值。 如果R
[单片机]
<font color='red'>STM32</font>硬件错误的<font color='red'>调试</font>技巧
如何解决STM32芯片Flash写保护导致无法下载程序,无法在线调试的问题
本文介绍了如何解决STM32芯片Flash写保护导致无法下载程序,无法在线调试的问题;如果您遇到相同的问题,希望本文可以带来一些帮助; 1 FLASH的写保护 如果对Flash设置了写保护,那就无法对Flash进行编程和擦除。 在开发STM32的时候,如果出现这种情况,通常仿真器都支持对Flash进行解锁,像jlink,stlink等仿真器都支持这个功能。 2 错误提示 在使用MDK进行调试的时候,出现报错 ==Flash Timeout.Reset Target and try it again==,具体如下图所示; 折腾了一番之后,并没有解决问题,因为使用的仿真器是stlink,因此下载了stlink utilit
[单片机]
如何解决<font color='red'>STM32</font>芯片Flash写保护导致无法下载程序,无法在线<font color='red'>调试</font>的问题
STM32单片机中OBG调试接口的介绍
OBG在单片机中的解释STM32单片机的内核(Cortex-M3)含有硬件调试模块,支持多种复杂的调试操作,硬件调试模块允许内核在取地址或者访问数据时停止-这就是我们在单片机开发和过程中可以在线仿真的保障。内核在停止时,其内部的状态与外部状态都是可以进行查询的,- 在单片机仿真调试中受到中断,通常为人为设置的断点,此时单片机中所有的变量,以及程序指针,CP,等地址指针都可以查询到状态。在调试过程中,设置了断点,当程序停止运行时,我们可以接着进行单步执行,跳出函数,进入函数等操作。还可以进行复位,使寄存器都回归到初始复位状态。 OBG调试接口 串行接口 JTAG调试接口 OBG调试框图 SWJ(serial wire and
[单片机]
<font color='red'>STM32</font>单片机中OBG<font color='red'>调试</font>接口的介绍
浅析STM32调试过程中的几个相关问题
总的来讲,单片机调试是单片机开发工作必不可少的环节。不管你愿不愿意,调试过程中总会有各种不期而遇的问题出现在我们面前来磨砺我们。这里分享几点STM32调试过程中与开发工具及IDE有关的几个常见问题,以供参考。 1、做低功耗调试时连接不上目标板 默认情况下,当MCU进入低功耗模式后,内核时钟停止工作,调试连接将中断。不过,通过设置DBGMCU寄存器控制位,即使进入低功耗模式,还是可以进行一定程度的调试。 在保证DGBMCU控制位正确配置前提下,还需注意SWD调试脚没有被配置为【analog state】模拟输入状态。我们在具体应用时为了降低功耗可能会将芯片的包括SWD调试脚在内的GPIO配置为模拟功能,这样会到导致调试器连接不上
[单片机]
浅析<font color='red'>STM32</font><font color='red'>调试</font>过程中的几个相关问题
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved