精华内容
下载资源
问答
  • STM32芯片烧录的三种方式介绍,MDK、STM32 ST-LINK Utility以及STM32CubeProgrammer1 资源概述2.MDK软件下载介绍3 STM32 ST-LINK Utility介绍4 STM32CubeProgrammer5 官方正版STLINK仿真器 1 资源概述 开发板:正点...

    1 概述

    1.1资源概述

    开发板:正点原子STM32F103 Nano开发板
    STM32 ST-LINK Utility版本:V4.5.0.0
    STM32CubeProgrammer版本:V2.4.0
    MDK版本:V5.23
    主控芯片型号:STM32F103RBT6
    正点原子开发板

    1.2 STM32串口烧录方式

    启动模式说明说明,我们选择系统存储器启动。
    启动模式说明
    内嵌的自举程序存放在系统存储区,由ST在生产线上写入,用于通过可用的串行接口对闪存存储器进行重新编程: ● 对于小容量、中容量和大容量的产品而言,可以通过USART1接口启用自举程序。串口烧录的原理就是利用这个自举程序读取串口的数据,对内部Flash进行擦写,实现程序的烧录。
    使用串口进行烧录,上位机可采用FLYMCU,然后通过USB转串口线(或者板)给目标设备进行烧录。需要注意的是,如果是M3内核非互联网型的板子这里的串口必须是串口1,对应为GPIO9和GPIO10。如果是M4内核,可以是下述端口。
    ● USART1(PA9/PA10)
    ● USART3(PB10/11 和 PC10/11)
    ● CAN2(PB5/13)
    ● USB OTG FS(PA11/12) 从设备模式(DFU:器件固件升级)。
    串口烧录工具
    BOOT1设为0,BOOT0设为1,按复位键即可进入串口下载模式,打开FLYMCU软件,选择正确的串口,点击读器件信息,显示连接成功。
    FlyMCU下载
    打开所需要下载的HEX文件,这里由于电路上没有自动复位进BOOT区的电路(正点原子部分高级一点的板子有),我们选择不使用RTS和DTR。点击开始编程。直至下载成功。
    在这里插入图片描述
    下载完成后,将BOOT0跳线跳到0,按一下Reset键,程序即可正常运行。
    使用这种串口方式烧录时,若选择STLINK进行烧录,将会报错。未检测到STLINK错误提示。需要使用另外的工具进行烧录。
    未检测到STLINK

    2.KEIL软件下载介绍

    可以使用KEIL内部集成的STLINK组件进行烧录,使用此种方式进行烧录时,将STLINK连接到电脑,在KEIL中可以检测到STLINK。检测到STLINK
    建立工程并编译通过后,可以实现内部集成的烧录工具实现对目标开发板(芯片)的烧录工作。
    使用KEIL进行烧录
    缺点是显而易见的,当我们工程文件缺失,只有烧录目标程序.bin或者.hex文件时,我们就不能通过这种方式进行烧录操作。接下来我给大家介绍两个ST官方的烧录软件,可以在ST官方网站上下载到。分别是STM32 ST-LINK Utility和STM32CubeProgrammer。

    3 STM32 ST-LINK Utility介绍

    3.1 windows操作系统

    上位机可采用ST官方的STLINK软件,然后通过STLINK模块给目标设备进行烧录。
    STLINK烧录方式
    此软件需要使用STLINK仿真烧录器,支持.bin/.src/.hex/.src/.s19五种格式的烧录文件下载。烧录文件在MDK软件编译工程时会自动生成。正点原子的例程烧录文件位于OBJ文件夹中(.hex)。如果是使用STM32CUBEIDE生成的工程,编译后烧录文件位于Debug文件夹中(.bin)。
    STM32 ST-LINK Utility
    这个软件支持开发板板载的STLINK V2.1进行烧录操作,不会提示需要固件升级等任何错误。具备烧录软件和芯片已烧软件比对灯功能。软件体积小巧,非常好用。

    3.2 Ubuntu操作系统中烧录

    3.2.1 软件安装

    软件直接使用命令行安装即可,UBUNTU的源自带此软件,无需在github上下载源码编译安装。

    //安装STLINK
    sudo apt install stlink-tools
    
    //查看STLINK的版本,确认是否安装成功,如果成功会返回版本号
    st-info --version
    
    //安装STLINK-GUI界面
    sudo apt install stlink-gui
    
    //使用命令行进行下载
    sudo st-flash write test.bin 0x8000000
    

    使用命令行进行软件的烧写工作,下载命令的格式,比如说可以使用st-flash erase对芯片进行擦除

    whs@whs-hp:~/Downloads$ st-flash
    invalid command line
    stlinkv1 command line: ./st-flash [--debug] [--reset] [--format <format>] [--flash=<fsize>] {read|write} /dev/sgX <path> <addr> <size>
    stlinkv1 command line: ./st-flash [--debug] /dev/sgX erase
    stlinkv2 command line: ./st-flash [--debug] [--reset] [--serial <serial>] [--format <format>] [--flash=<fsize>] {read|write} <path> <addr> <size>
    stlinkv2 command line: ./st-flash [--debug] [--serial <serial>] erase
    stlinkv2 command line: ./st-flash [--debug] [--serial <serial>] reset
                           Use hex format for addr, <serial> and <size>.
                           fsize: Use decimal, octal or hex by prefix 0xXXX for hex, optionally followed by k=KB, or m=MB (eg. --flash=128k)
                           Format may be 'binary' (default) or 'ihex', although <addr> must be specified for binary format only.
                           ./st-flash [--version]
    example write option byte: ./st-flash --debug --reset --area=option write 0xXXXXXXXX
    example read option byte: ./st-flash --debug --reset --area=option read > option_byte
    
    

    3.2.2 软件烧录

    软件下载示例,烧录文件为bin格式,需要带地址信息,sudo为非必须的,这里使用的版本是1.6.0

    whs@whs-hp:~/STM32CubeIDE/workspace_1.6.1/Cube_fl03_led/Debug$ sudo st-flash write Cube_fl03_led.bin 0x8000000
    [sudo] whs 的密码: 
    st-flash 1.6.0
    2021-08-27T00:28:36 INFO common.c: Loading device parameters....
    2021-08-27T00:28:36 INFO common.c: Device connected is: F1 Medium-density device, id 0x20036410
    2021-08-27T00:28:36 INFO common.c: SRAM size: 0x5000 bytes (20 KiB), Flash: 0x20000 bytes (128 KiB) in pages of 1024 bytes
    2021-08-27T00:28:36 INFO common.c: Attempting to write 15400 (0x3c28) bytes to stm32 address: 134217728 (0x8000000)
    Flash page at addr: 0x08003c00 erased
    2021-08-27T00:28:36 INFO common.c: Finished erasing 16 pages of 1024 (0x400) bytes
    2021-08-27T00:28:36 INFO common.c: Starting Flash write for VL/F0/F3/F1_XL core id
    2021-08-27T00:28:36 INFO flash_loader.c: Successfully loaded flash loader in sram
     16/16 pages written
    2021-08-27T00:28:37 INFO common.c: Starting verification of write complete
    2021-08-27T00:28:37 INFO common.c: Flash written and verified! jolly good!
    whs@whs-hp:~/STM32CubeIDE/workspace_1.6.1/Cube_fl03_led/Debug$ 
    

    当烧录文件为hex格式时,由于hex文件里边包含地址信息,因此不需要再指定地址了,但是需要指明烧录的格式。

    whs@whs-hp:/media/whs/HP_D/STM32/F103/trunk/FSMLED/Project$ st-flash --format ihex write output\(mdk\).hex
    

    3.2.3 使用GUI界面进行烧录

    安装STLINK-GUI后,可以使用GUI程序进行下载,GUI的显示界面如下
    在这里插入图片描述

    3.2.4 更多详细信息

    命令行模式仅支持V1和V2版本的仿真器,并不支持V3版本的仿真器。
    更多详细信息,可以参见GitHub的官方资料

    https://github.com/stlink-org/stlink

    4 STM32CubeProgrammer

    4.1 使用STLINK进行下载

    STM32CubeProgrammer软件是ST新推出的烧录软件,支持更多的方式设置,官方定位是替代ST-LINK Utility。打开如下图所示,支持STLINK、USB、UART以及OTA(均需要对应的烧录工具)下载,支持SWD和JTAG。但是需要说明的是,这个软件烧录时,需要STLINK固件为最新。使用正点原子Nano开发板时,会提示软件非最新,不能进行连接。
    PROGRAMMER软件
    弹出的固件需要升级的错误
    错误
    如果买的是官方出品的STLINK,可以正常对固件进行升级,如果不是官方的烧录器,升级前请三思,升级后有可能导致烧录器不能正常使用。下图为点击firmware update后出现的弹框。
    在这里插入图片描述
    使用正点原子Nano开发板也无需担心会升级导致不能用,因为你尝试升级时会弹出另外一个提示,需要额外的9856B空间,不能进行升级,原因是我们板载的STLINK芯片采用的STM32F103C8T6只有64K空间,这部分空间已经全部用完,不能再写入更新更大的固件。
    在这里插入图片描述
    另外这个软件也集成在STM32CUBEIDE软件中,STM32CUBEIDE为ST将eclipse、STM32CUBEMX和STM32CUBEPROGRAMMER集成整合到一起的综合编程软件,目前用的人还很少,挺好用,而且免费,跨平台。连接成功的示意图如下,默认会把芯片内部的程序读出来,可以对此程序进行另存为等操作。
    连接成功
    使用此烧录工具,烧录时还可以对芯片进行读写保护,避免芯片被恶意读出盗窃烧录底层。
    读保护
    在ubuntu中此软件和windows下是相同的。

    4.2 使用串口进行下载

    我们在此软件中,可以使用串口进行连接烧录,这样做的好处是不需要使用第三方串口烧录工具,另外cubeprogrammer也不会对STLINK的版本信息进行核验。

    1.BOOT设置,将BOOT1跳到0(开发板已经默认拉到地),BOOT0跳到1(3.3V)。按一下RESET按键
    BOOT设置
    2,打开软件,选择Uart和正确的COM口,由于用的是串口,因此就和stlink无关了,用一个USB转串口线也可以进行下载。
    选择串口
    3,连接成功后如下
    连接成功
    4,选择要下载的文件下载,下图所示已经下载成功。
    下载文件
    5,将BOOT0跳线还原到BOOT0。若上图勾选了Run after programming,则无需按Reset即会运行新程序,若没有勾选,按一下Reset按键。

    5 官方正版STLINK仿真器

    5.1 STLINK V3 mini下载器

    这里我推荐一款官方的正版仿真器,即STLINK V3 MINI,ST官方近两年推出,采用了STM32F723的芯片,比常见的STLINK V2拥有更多的功能,更快的速度。
    在这里插入图片描述

    这个仿真器非常小,比通常的U盘还小一号,且排线为14P 1.27mm间距的排线。因此不支持常见的2.54杜邦线连接,需要额外的转接板进行转接。这里需要特别注意。此款仿真器支持一个虚拟的串口(13脚和14脚),支持SWD和JTAG烧录,端口定义如下:
    14P端口定义
    嘉立创白嫖自制的转接板,此板的J4插座还支持NUCLEO的SWD扩展口的转接,按键为RESET按键,可以下载完成后手动对烧录好的芯片进行复位。
    在这里插入图片描述
    背面引出的串口,本想放在正面的,结果实物比封装大,翻车了,而且1.27的插件不是一般难焊,很容易连锡。
    在这里插入图片描述
    STLINK V3版本的速度比V2的要快,缺点是不支持山寨芯片,接上后提示无法连接到目标,而STLINK V2是支持山寨STM32芯片的。目前V3系列暂时未发现网上有仿造的产品出售。这款性价比比较高,淘宝价格80元,推荐各位购买。

    5.2 集成在官方开发板上的STLINK

    官方的开发板集成了STLINK,这个STLINK可以对外进行烧录。这块部分可以裁下来单独使用。当烧录外部设备时,需要将外部烧录跳线拔下来,然后将烧录口和目标板通过杜邦线进行连接。不同的开发板对应的STLINK版本不同,F103对应的是V2.1,F7开发板对应的是V3.0。
    官方开发板带的烧录工具
    可以做一个6PIN转20PIN的转接板,转接到20pin上,成为一个标准的下载器。
    在这里插入图片描述

    6 连接异常处理

    6.1 能连接但下载报错解决方案

    使用杜邦线进行SWD连接时,如果是散线或者线缆过长,会出现KEIL能连接上,但是下载报错(flash错误或者M3错误)的故障。将线缆更换为排线或者降低线缆的长度可以解决这个问题。
    错误线缆连接

    6.2 特殊IO口使用导致烧录一次程序后SWD口不能用

    JTAG或者SWD端口被占用,但是却没有进行正确的配置。
    在开发STM32F407芯片时,调试18B20温度程序时发现一个问题,当下载完一次程序后,SW就失去连接
    失去连接
    强制烧录时报错信息如下:No target connected
    报错
    报错信息Error:Flash Download failed-Target DLL has been cancelled
    报错
    使用utility连接也会报错,报错信息如下:Cannot connect to target
    报错信息
    按照提示,在烧录时按Reset按键,成功烧录了软件。使用一行行注释排除的方法,最后定位在DS18B20_Init初始化函数这。程序使用了PB15作为了18B20的输入,这个口也是JTAG的接口,在使用时,不能按照常规GPIO口进行配置。使用时,需要先禁止JTAG,然后使能SWD。如果弄成了最后一种模式就SW下载方式无效,需要按住Reset复位重新连接烧录了。
    在这里插入图片描述
    为了验证这个想法,在程序中将A15改为B15。更改初始化函数

    u8 DS18B20_Init(void)
    {
    	GPIO_InitTypeDef  GPIO_InitStructure;
    
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOA时钟,改为使能GPIOB时钟
    
      //GPIOA15,改为了GPIOB15
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
      GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
      DS18B20_Rst();
      return DS18B20_Check();
    }
    
    

    更改头文件定义

    //IO方向设置
    #define DS18B20_IO_IN()  {GPIOB->MODER&=0XCFFFFFFF;GPIOB->MODER|=0;}	//PA15输入模式,改为PB15
    #define DS18B20_IO_OUT() {GPIOB->MODER&=0XCFFFFFFF;GPIOB->MODER|=0x40000000;} 	//PA15输出模式,改为PB15
     
    IO操作函数											   
    #define	DS18B20_DQ_OUT PBout(15) //数据端口	PA15,改为PB15
    #define	DS18B20_DQ_IN  PBin(15)  //数据端口	PA15,改为PB15
    

    更改后,可以通过编译,下载后,KEIL也能扫描到设备。
    通过编译

    7 stlink对芯片的部分Sector进行擦除

    在使用Bootloader+App的使用方式时,我们烧录App时,如果每次都对全片进行擦除,那么每次的Bootloard将会被我们擦除掉,导致程序需要下载两遍。我们可以选择对部分的Sector进行擦除,而不是全部。
    案例:某个Bootloader对应开始地址为0x8000000,结束地址为0x80042B0对应地址
    APP应用对应的首地址为0x8010000
    对应首地址
    结束地址为0x8015BD0
    结束地址
    当我们不希望擦除Bootloader时,我们可以选择Sector擦除,擦除APP对应的地址段。
    擦除APP
    此时程序回退到没有下载APP时的运行状态。可以继续下载新的APP应用程序。

    展开全文
  • 基于STM32的录音机设计(STM32F103+VS1053B)

    千次阅读 多人点赞 2021-06-09 19:06:35
    MCU: STM32F103C8T6 开发软件: Keil5 音频模块: VS1053B 录音文件存储设备: SD卡,采用SPI协议驱动 显示屏: SPI接口的0.96寸OLED 代码风格: 采用寄存器编程,代码简洁、执行效率高、注释到位、移植方便。 项目...

    一、环境介绍

    MCU:  STM32F103C8T6

    开发软件:  Keil5

    音频模块:  VS1053B

    录音文件存储设备:  SD卡,采用SPI协议驱动

    显示屏:  SPI接口的0.96寸OLED

    代码风格:  采用寄存器编程,代码简洁、执行效率高、注释到位、移植方便。

    项目完整源代码下载地址(下载即可编译运行测试):  https://download.csdn.net/download/xiaolong1126626497/19520781

    二、功能介绍

    这是基于STM32F103C8T6设计的录音机功能,支持的功能如下:

    1.  按下按键1启动自动录音,默认为5秒录音一次,录音完毕自动保存在SD指定目录下。文件名称采用当前时间命名;音频文件格式采用WAV格式存储。

    2.  按下按键2启动手动录音,按键按下之后开始录音,再次按下结束录音,录音完毕之后,文件也是一样的保存在SD卡里。

    3. SD卡文件系统采用FAT32格式,STM32移植了FATFS开源文件系统对SD卡进行读写操作。

    4. OLED显示屏用于显示当前录音机的状态:  空闲、录音、回放等状态。

    5. 按下按键3,启动自动回放功能。自动扫描目录,按顺序播放录音文件。

    技术介绍:

    1.  SD卡采用SPI协议驱动,因为对速度没有很高要求,SPI协议已经完全满足;如果要更高的速度,可以采用SDIO协议。

    2.  音频模块采用VS1053B,这个芯片支持IIS和SPI协议。我这里采用的是SPI协议驱动,SPI比较简单,代码也好移植,可以很方便的移植到其他单片机上运行。VS1053功能比较强大,支持录音、解码播放。

    3.  文件系统采用的是FATFS文件系统,这个文件系统功能比较完善,使用免费,支持FAT16、FAT32等格式。底层也比较好适配移植。当前,除了FATFS以外,还有很多其他的嵌入式文件系统可以选择,移植都大同小异。

    4. OLED显示屏是0.96寸的。采用SPI协议驱动,主要是显示一些状态,SPI刷屏比较快,这款OLED也支持IIC接口。

    5. VS1053模块上没有喇叭设备,可以适应耳机或者音箱听回放的录音。

     

    硬件与STM32的接线说明:

    OLED显示屏:
    D0----SCK-----PB14
    D1----MOSI----PB13
    RES—复位(低电平有效)—PB12
    DC---数据和命令控制管脚—PB1
    CS---片选引脚-----PA7

    VS1053:
    #define VS1053_DREQ     PAin(11)      //DREQ  数据请求
    #define VS1053_RESET    PAout(12)   //RST   硬件复位--低电平有效
    #define VS1053_XCS      PAout(13)      //XCS   片选--低电平有效
    #define VS1053_XDCS     PAout(14)      //XDCS  用于数据片选、字节同步
    #define VS1053_SCLK     PAout(15)
    #define VS1053_OUTPUT   PBout(3)
    #define VS1053_INPUT    PBin(4)

    SD卡接口:
    5V----5V
    GND---GND
    SPI1_MOSI---PA7
    SPI1_MISO---PA6
    SPI1_CS---PA4
    SPI1_SCK--PA5
     

    三、使用的相关硬件

    STM32F103C8T6系统板: 

    OLED显示屏: 

    VS1053: 

    SD卡卡槽: 

     

     

    四、操作说明

    开发板有一个复位键和一个K0按键。

    程序下载:

     

    程序支持三种模式:

    因为开发板只有一个K0按键,所以三种模式都是通过一个按键进行切换的。

    一个按键是通过按下的计数方式进行切换的,切换的顺序是自动录音模式、手动录音模式、回放模式。

    (1)自动录音模式:按下一次按键后,进入自动录音模式,自动录音模式下,录音5秒自动退出,退出后自动启动播放状态,就是播放刚才5秒录制的音频,播放过程中按下按键可以退出播放状态。

    (2)手动录音模式:第二次按下K0按键后,进入手动录音模式,手动录音模式下,可以长时间录音,如果要结束录音,按下K0按键即可结束;结束后自动启动播放状态,就是播放刚才录制的音频,播放过程中按下按键可以退出播放状态。

    (3)回放模式:第三次按下K0按键后,进入回放模式,自动扫描wav目录,进行顺序播放音频文件。

        播放过程中可以按下K0按键退出回放模式。
    每次录音后的文件是存放在SD卡根目录下的wav目录下。
    每个状态都会在OLED显示屏上显示
    也会同时通过串口打印到串口调试助手终端。

    五、SD卡上存放的文件

    SD卡上有两个目录:font目录和wav目录。
    font目录下存放16x16字库文件。
    wav目录下存放录音的音频文件。
     

    六、部分源码

    6.1 VS1053.c   这是VS1053的驱动代码

    #include "vs1053b.h"	
    
    /*
    函数功能:移植接口--SPI时序读写一个字节
    函数参数:data:要写入的数据
    返 回 值:读到的数据
    */
    u8 VS1053_SPI_ReadWriteByte(u8 tx_data)
    {			  	 
    	u8 rx_data=0;				 
      u8 i;
      for(i=0;i<8;i++)
    	{
    		VS1053_SCLK=0;  
    		if(tx_data&0x80){VS1053_OUTPUT=1;}
    		else {VS1053_OUTPUT=0;}
    		tx_data<<=1;	
    		VS1053_SCLK=1;
    		rx_data<<=1;
    		if(VS1053_INPUT)rx_data|=0x01;
    	}
    	return rx_data; 
    }
    
    
    /*
    函数功能:初始化VS1053的IO口	 
    */
    void VS1053_Init(void)
    {
    	 RCC->APB2ENR|=1<<0;
    	 AFIO->MAPR&=~(0x7<<24);  //释放PA13/14/15
    	 AFIO->MAPR|=0x4<<24;
    	
    	 RCC->APB2ENR|=1<<2;
    	 RCC->APB2ENR|=1<<3;
    	 
    	 GPIOA->CRH&=0x00000FFF;
    	 GPIOA->CRH|=0x33338000;
    	  
    	 GPIOB->CRL&=0xFFF00FFF;
    	 GPIOB->CRL|=0x00083000;
    	
    	 VS1053_SCLK=1;
    	 VS1053_XCS=1;
         VS1053_RESET=1;
    
    }	
    
    
    /*
    函数功能:软复位VS10XX
    */
    void VS1053_SoftReset(void)
    {	 
    	u8 retry=0;  				   
    	while(VS1053_DREQ==0); 							//等待软件复位结束	   
    	VS1053_SPI_ReadWriteByte(0Xff);			//启动传输
    	retry=0;
    	while(VS1053_ReadReg(SPI_MODE)!=0x0800)	// 软件复位,新模式  
    	{
    		VS1053_WriteCmd(SPI_MODE,0x0804);		// 软件复位,新模式	    
    		DelayMs(2);//等待至少1.35ms 
    		if(retry++>100)break; 	  
    	}	
    	while(VS1053_DREQ==0);//等待软件复位结束	 
    	retry=0;
    	while(VS1053_ReadReg(SPI_CLOCKF)!=0X9800)//设置VS10XX的时钟,3倍频 ,1.5xADD 
    	{
    		VS1053_WriteCmd(SPI_CLOCKF,0X9800);	//设置VS10XX的时钟,3倍频 ,1.5xADD
    		if(retry++>100)break; 	    
    	}	 
    	DelayMs(20);
    } 
    
    
    /*
    函数 功 能:硬复位MP3
    函数返回值:1:复位失败;0:复位成功	
    */
    u8 VS1053_Reset(void)
    {
    	u8 retry=0;
    	VS1053_RESET=0;
    	DelayMs(20);
    	VS1053_XDCS=1;//取消数据传输
    	VS1053_XCS=1; //取消数据传输
    	VS1053_RESET=1;	   
    	while(VS1053_DREQ==0&&retry<200)//等待DREQ为高
    	{
    		retry++;
    		DelayUs(50);
    	}
    	DelayMs(20);	
    	if(retry>=200)return 1;
    	else return 0;	    		 
    }
    
    
    /*
    函数功能:向VS10XX写命令
    函数参数:
    				address:命令地址
    				data   :命令数据
    */
    void VS1053_WriteCmd(u8 address,u16 data)
    {  
    	while(VS1053_DREQ==0);	//等待空闲		   	   
    	VS1053_XDCS=1; 	 
    	VS1053_XCS=0; 	 
    	VS1053_SPI_ReadWriteByte(VS_WRITE_COMMAND);//发送VS10XX的写命令
    	VS1053_SPI_ReadWriteByte(address); 	//地址
    	VS1053_SPI_ReadWriteByte(data>>8); 	//发送高八位
    	VS1053_SPI_ReadWriteByte(data);	 		//第八位
    	VS1053_XCS=1;            
    } 
    
    
    /*
    函数参数:向VS1053写数据
    函数参数:data:要写入的数据
    */
    void VS1053_WriteData(u8 data)
    {
    	VS1053_XDCS=0;   
    	VS1053_SPI_ReadWriteByte(data);
    	VS1053_XDCS=1;      
    }
    
    
    /*
    函数功能:读VS1053的寄存器 
    函数参数:address:寄存器地址
    返回值:读到的值
    */
    u16 VS1053_ReadReg(u8 address)
    { 
    	u16 temp=0;   	
      while(VS1053_DREQ==0);//非等待空闲状态   	
    	VS1053_XDCS=1;       
    	VS1053_XCS=0;        
    	VS1053_SPI_ReadWriteByte(VS_READ_COMMAND);//发送VS10XX的读命令
    	VS1053_SPI_ReadWriteByte(address);       	//地址
    	temp=VS1053_SPI_ReadWriteByte(0xff); 		  //读取高字节
    	temp=temp<<8;
    	temp+=VS1053_SPI_ReadWriteByte(0xff); 		//读取低字节
    	VS1053_XCS=1;      
       return temp; 
    }  
    
    
    /*
    函数功能:读取VS1053的RAM
    函数参数:addr:RAM地址
    返 回 值:读到的值
    */
    u16 VS1053_ReadRAM(u16 addr) 
    { 
    	u16 res;			   	  
     	VS1053_WriteCmd(SPI_WRAMADDR, addr); 
    	res=VS1053_ReadReg(SPI_WRAM);  
     	return res;
    } 
    
    
    /*
    函数功能:写VS1053的RAM
    函数参数:
    				addr:RAM地址
    				val:要写入的值 
    */
    void VS1053_WriteRAM(u16 addr,u16 val) 
    {  		   	  
     	VS1053_WriteCmd(SPI_WRAMADDR,addr);	//写RAM地址 
    	while(VS1053_DREQ==0); 							//等待空闲	   
    	VS1053_WriteCmd(SPI_WRAM,val); 			//写RAM值 
    } 
    
    
    /*
    函数参数:发送一次音频数据,固定为32字节
    返 回 值:0,发送成功
    				  1,本次数据未成功发送   
    */ 
    u8 VS1053_SendMusicData(u8* buf)
    {
    	u8 n;
    	if(VS1053_DREQ!=0)  //送数据给VS10XX
    	{			   	 
    		VS1053_XDCS=0;  
        for(n=0;n<32;n++)
    		{
    			VS1053_SPI_ReadWriteByte(buf[n]);	 			
    		}
    		VS1053_XDCS=1;     				   
    	}else return 1;
    	return 0;//成功发送了
    }
    
    
    /*
    函数参数:发送一次音频数据,固定为32字节
    返 回 值:0,发送成功
    				  1,本次数据未成功发送   
    */ 
    void VS1053_SendMusicByte(u8 data)
    {
    	u8 n;
    	while(VS1053_DREQ==0){}	   	 
    	VS1053_XDCS=0;  
    	VS1053_SPI_ReadWriteByte(data);	 			
    	VS1053_XDCS=1;     				   
    }
    
    
    /*
    函数功能:设定VS1053播放的音量
    函数参数:volx:音量大小(0~254)
    */
    void VS1053_SetVol(u8 volx)
    {
        u16 volt=0; 			      //暂存音量值
        volt=254-volx;			    //取反一下,得到最大值,表示最大的表示 
    	  volt<<=8;
        volt+=254-volx;					//得到音量设置后大小
        VS1053_WriteCmd(SPI_VOL,volt);//设音量 
    }
    
    
    /*--------------------------------------录音功能-----------------------------------------------------*/
    
    
    /*
    函数功能:vs10xx装载patch
    函数参数:
    				patch:patch首地址
    				len  :patch长度
    */
    void VS1053_LoadPatch(u16 *patch,u16 len) 
    {
    	u16 i; 
    	u16 addr, n, val; 	  			   
    	for(i=0;i<len;) 
    	{ 
    		addr = patch[i++]; 
    		n    = patch[i++]; 
    		if(n & 0x8000U) //RLE run, replicate n samples 
    		{ 
    			n  &= 0x7FFF; 
    			val = patch[i++]; 
    			while(n--)VS1053_WriteCmd(addr, val);  
    		}
    		else //copy run, copy n sample 
    		{ 
    			while(n--) 
    			{ 
    				val = patch[i++]; 
    				VS1053_WriteCmd(addr, val); 
    			} 
    		} 
    	} 	
    }
    
    
    /*
    函数参数:初始化WAV头
    */
    void VS1053_RecoderWavInit(__WaveHeader* wavhead) //初始化WAV头			   
    {
    	wavhead->riff.ChunkID=0X46464952;	//"RIFF"
    	wavhead->riff.ChunkSize=0;				//还未确定,最后需要计算
    	wavhead->riff.Format=0X45564157; 	//"WAVE"
    	wavhead->fmt.ChunkID=0X20746D66; 	//"fmt "
    	wavhead->fmt.ChunkSize=16; 				//大小为16个字节
    	wavhead->fmt.AudioFormat=0X01; 		//0X01,表示PCM;0X01,表示IMA ADPCM
     	wavhead->fmt.NumOfChannels=1;			//单声道
     	wavhead->fmt.SampleRate=8000;			//8Khz采样率 采样速率
     	wavhead->fmt.ByteRate=wavhead->fmt.SampleRate*2;//16位,即2个字节
     	wavhead->fmt.BlockAlign=2;				//块大小,2个字节为一个块
     	wavhead->fmt.BitsPerSample=16;		//16位PCM
      wavhead->data.ChunkID=0X61746164;	//"data"
     	wavhead->data.ChunkSize=0;				//数据大小,还需要计算  
    }
    
    //VS1053的WAV录音有bug,这个plugin可以修正这个问题 							    
    const u16 VS1053_WavPlugin[40]=/* Compressed plugin */ 
    { 
    		0x0007, 0x0001, 0x8010, 0x0006, 0x001c, 0x3e12, 0xb817, 0x3e14, /* 0 */ 
    		0xf812, 0x3e01, 0xb811, 0x0007, 0x9717, 0x0020, 0xffd2, 0x0030, /* 8 */ 
    		0x11d1, 0x3111, 0x8024, 0x3704, 0xc024, 0x3b81, 0x8024, 0x3101, /* 10 */ 
    		0x8024, 0x3b81, 0x8024, 0x3f04, 0xc024, 0x2808, 0x4800, 0x36f1, /* 18 */ 
    		0x9811, 0x0007, 0x0001, 0x8028, 0x0006, 0x0002, 0x2a00, 0x040e,  
    }; 
    
    
    /*
    函数功能:激活PCM 录音模式
    函数参数:
    				agc:0,自动增益
            1024相当于1倍
            512相当于0.5倍
            最大值65535=64倍		  
    */
    void VS1053_RecoderInit(u16 agc)
    {
    	//如果是IMA ADPCM,采样率计算公式如下:
     	//采样率=CLKI/256*d;	
    	//假设d=0,并2倍频,外部晶振为12.288M.那么Fc=(2*12288000)/256*6=16Khz
    	//如果是线性PCM,采样率直接就写采样值 
      VS1053_WriteCmd(SPI_BASS,0x0000);    
     	VS1053_WriteCmd(SPI_AICTRL0,8000);	//设置采样率,设置为8Khz
     	VS1053_WriteCmd(SPI_AICTRL1,agc);		//设置增益,0,自动增益.1024相当于1倍,512相当于0.5倍,最大值65535=64倍	
     	VS1053_WriteCmd(SPI_AICTRL2,0);		  //设置增益最大值,0,代表最大值65536=64X
     	VS1053_WriteCmd(SPI_AICTRL3,6);		  //左通道(MIC单声道输入)
    	VS1053_WriteCmd(SPI_CLOCKF,0X2000);	//设置VS10XX的时钟,MULT:2倍频;ADD:不允许;CLK:12.288Mhz
    	VS1053_WriteCmd(SPI_MODE,0x1804);		//MIC,录音激活    
     	DelayMs(5);					//等待至少1.35ms 
     	VS1053_LoadPatch((u16*)VS1053_WavPlugin,40);//VS1053的WAV录音需要patch
    }
    
    

     

    6.2   SD.c  这是SD卡的驱动代码

    #include "sdcard.h"			   
    static u8  SD_Type=0;  //存放SD卡的类型
    
    /*
    函数功能:SD卡底层接口,通过SPI时序向SD卡读写一个字节
    函数参数:data是要写入的数据
    返 回 值:读到的数据
    */
    u8 SDCardReadWriteOneByte(u8 DataTx)
    {		 
        u16 cnt=0;				 
        while((SPI1->SR&1<<1)==0)		 //等待发送区空--等待发送缓冲为空	
        {
          cnt++;
          if(cnt>=65530)return 0; 	  //超时退出  u16=2个字节
        }	
        SPI1->DR=DataTx;	 	  		      //发送一个byte 
        cnt=0;
        while((SPI1->SR&1<<0)==0) 		//等待接收完一个byte   
        {
          cnt++;
          if(cnt>=65530)return 0;	   //超时退出
        }	  						    
        return SPI1->DR;          		//返回收到的数据
    }
    
    
    /*
    函数功能:底层SD卡接口初始化
    SPI1接口---SD卡接线原理
    5V----5V
    GND---GND
    SPI1_MOSI---PA7
    SPI1_MISO---PA6
    SPI1_CS---PA4
    SPI1_SCK--PA5
    */
    void SDCardSpiInit(void)
    {
      /*1. 开启时钟*/
     	RCC->APB2ENR|=1<<2;		    //使能PORTA时钟
      
      /*2. 配置GPIO口模式*/
      GPIOA->CRL&=0x0000FFFF;
      GPIOA->CRL|=0xB8B30000;
      
      /*3. 上拉*/
      GPIOA->ODR|=1<<4;
    	
    		/*SPI1基本配置*/
    	RCC->APB2ENR|=1<<12;    //开启SPI1时钟
    	RCC->APB2RSTR|=1<<12;
    	RCC->APB2RSTR&=~(1<<12);
    	
    	SPI1->CR1=0X0; 		//清空寄存器
    	SPI1->CR1|=0<<15; //选择“双线双向”模式
    	SPI1->CR1|=0<<11; //使用8位数据帧格式进行发送/接收;
    	SPI1->CR1|=0<<10; //全双工(发送和接收);
    	SPI1->CR1|=1<<9;  //启用软件从设备管理
    	SPI1->CR1|=1<<8;  //NSS
    	SPI1->CR1|=0<<7;  //帧格式,先发送高位
    	SPI1->CR1|=0x0<<3;//当总线频率为36MHZ时,SPI速度为18MHZ,高速。
    	SPI1->CR1|=1<<2;  //配置为主设备
    	SPI1->CR1|=1<<1;  //空闲状态时, SCK保持高电平。
    	SPI1->CR1|=1<<0;  //数据采样从第二个时钟边沿开始。
    	SPI1->CR1|=1<<6;  //开启SPI设备。
    }
    
    /*
    函数功能:取消选择,释放SPI总线
    */
    void SDCardCancelCS(void)
    {
    	SDCARD_CS=1;
     	SDCardReadWriteOneByte(0xff);//提供额外的8个时钟
    }
    
    
    /*
    函数 功 能:选择sd卡,并且等待卡准备OK
    函数返回值:0,成功;1,失败;
    */
    u8 SDCardSelectCS(void)
    {
    	SDCARD_CS=0;
    	if(SDCardWaitBusy()==0)return 0;//等待成功
    	SDCardCancelCS();
    	return 1;//等待失败
    }
    
    
    /*
    函数 功 能:等待卡准备好
    函数返回值:0,准备好了;其他,错误代码
    */
    u8 SDCardWaitBusy(void)
    {
    	u32 t=0;
    	do
    	{
    		if(SDCardReadWriteOneByte(0XFF)==0XFF)return 0;//OK
    		t++;		  
    	}while(t<0xFFFFFF);//等待 
    	return 1;
    }
    
    
    /*
    函数功能:等待SD卡回应
    函数参数:
    					Response:要得到的回应值
    返 回 值:
    					0,成功得到了该回应值
    					其他,得到回应值失败
    */
    u8 SDCardGetAck(u8 Response)
    {
    	u16 Count=0xFFFF;//等待次数	   						  
    	while((SDCardReadWriteOneByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应  	  
    	if(Count==0)return SDCard_RESPONSE_FAILURE;//得到回应失败   
    	else return SDCard_RESPONSE_NO_ERROR;//正确回应
    }
    
    
    /*
    函数功能:从sd卡读取一个数据包的内容
    函数参数:
    				buf:数据缓存区
    				len:要读取的数据长度.
    返回值:
    			0,成功;其他,失败;	
    */
    u8 SDCardRecvData(u8*buf,u16 len)
    {			  	  
    	if(SDCardGetAck(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE
        while(len--)//开始接收数据
        {
            *buf=SDCardReadWriteOneByte(0xFF);
            buf++;
        }
        //下面是2个伪CRC(dummy CRC)
        SDCardReadWriteOneByte(0xFF);
        SDCardReadWriteOneByte(0xFF);									  					    
        return 0;//读取成功
    }
    
    
    /*
    函数功能:向sd卡写入一个数据包的内容 512字节
    函数参数:
    					buf 数据缓存区
    					cmd 指令
    返 回 值:0表示成功;其他值表示失败;
    */
    u8 SDCardSendData(u8*buf,u8 cmd)
    {	
    	u16 t;		  	  
    	if(SDCardWaitBusy())return 1;  //等待准备失效
    	SDCardReadWriteOneByte(cmd);
    	if(cmd!=0XFD)//不是结束指令
    	{
    		for(t=0;t<512;t++)SDCardReadWriteOneByte(buf[t]);//提高速度,减少函数传参时间
    	    SDCardReadWriteOneByte(0xFF); //忽略crc
    	    SDCardReadWriteOneByte(0xFF);
    		  t=SDCardReadWriteOneByte(0xFF); //接收响应
    		if((t&0x1F)!=0x05)return 2;   //响应错误									  					    
    	}						 									  					    
        return 0;//写入成功
    }
    
    
    
    /*
    函数功能:向SD卡发送一个命令
    函数参数:
    				u8 cmd   命令 
    				u32 arg  命令参数
    				u8 crc   crc校验值	
    返回值:SD卡返回的响应
    */												  
    u8 SendSDCardCmd(u8 cmd, u32 arg, u8 crc)
    {
    	u8 r1;	
    	u8 Retry=0; 
    		
    	SDCardCancelCS();               //取消上次片选
    	if(SDCardSelectCS())return 0XFF;//片选失效 
    	//发送数据
    	SDCardReadWriteOneByte(cmd | 0x40);//分别写入命令
    	SDCardReadWriteOneByte(arg >> 24);
    	SDCardReadWriteOneByte(arg >> 16);
    	SDCardReadWriteOneByte(arg >> 8);
    	SDCardReadWriteOneByte(arg);	  
    	SDCardReadWriteOneByte(crc); 
    	if(cmd==SDCard_CMD12)SDCardReadWriteOneByte(0xff);//Skip a stuff byte when stop reading
    	Retry=0X1F;
    	do
    	{
    		r1=SDCardReadWriteOneByte(0xFF);
    	}while((r1&0X80) && Retry--);	  //等待响应,或超时退出
       return r1;	//返回状态值
    }	
    
    
    
    /*
    函数功能:获取SD卡的CID信息,包括制造商信息
    函数参数:u8 *cid_data(存放CID的内存,至少16Byte)	  
    返 回 值:
    					0:成功,1:错误				
    */
    u8 GetSDCardCISDCardOutnfo(u8 *cid_data)
    {
        u8 r1;	   
        //发SDCard_CMD10命令,读CID
        r1=SendSDCardCmd(SDCard_CMD10,0,0x01);
        if(r1==0x00)
    	  {
    			r1=SDCardRecvData(cid_data,16);//接收16个字节的数据	 
        }
    	SDCardCancelCS();//取消片选
    	if(r1)return 1;
    	else return 0;
    }	
    
    
    /*
    函数说明:
    					获取SD卡的CSD信息,包括容量和速度信息
    函数参数:
    					u8 *cid_data(存放CID的内存,至少16Byte)	    
    返 回 值:
    					0:成功,1:错误	
    */
    u8 GetSDCardCSSDCardOutnfo(u8 *csd_data)
    {
    	u8 r1;	 
    	r1=SendSDCardCmd(SDCard_CMD9,0,0x01);    //发SDCard_CMD9命令,读CSD
    	if(r1==0)
    	{
    		r1=SDCardRecvData(csd_data, 16);//接收16个字节的数据 
    	}
    	SDCardCancelCS();//取消片选
    	if(r1)return 1;
    	else return 0;
    }  
    
    
    /*
    函数功能:获取SD卡的总扇区数(扇区数)   
    返 回 值:
    				0表示容量检测出错,其他值表示SD卡的容量(扇区数/512字节)
    说   明:
    				每扇区的字节数必为512字节,如果不是512字节,则初始化不能通过.	
    */
    u32 GetSDCardSectorCount(void)
    {
        u8 csd[16];
        u32 Capacity;  
    	  u16 csize;  					    
        if(GetSDCardCSSDCardOutnfo(csd)!=0) return 0;	//取CSD信息,如果期间出错,返回0
        if((csd[0]&0xC0)==0x40)  //SDHC卡,按照下面方式计算
        {	
    			csize = csd[9] + ((u16)csd[8] << 8) + 1;
    			Capacity = (u32)csize << 10;//得到扇区数	 		   
        }
        return Capacity;
    }
    
    
    
    /*
    函数功能: 初始化SD卡
    返 回 值: 非0表示初始化失败!
    */
    u8 SDCardDeviceInit(void)
    {
      u8 r1;      // 存放SD卡的返回值
      u16 retry;  // 用来进行超时计数
      u8 buf[4];  
    	u16 i;
    	SDCardSpiInit();		//初始化底层IO口
    	
     	for(i=0;i<10;i++)SDCardReadWriteOneByte(0XFF); //发送最少74个脉冲
    	retry=20;
    	do
    	{
    		r1=SendSDCardCmd(SDCard_CMD0,0,0x95);//进入IDLE状态 闲置
    	}while((r1!=0X01) && retry--);
     	SD_Type=0;   //默认无卡
    	if(r1==0X01)
    	{
    		if(SendSDCardCmd(SDCard_CMD8,0x1AA,0x87)==1)  //SD V2.0
    		{
    			for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);
    			if(buf[2]==0X01&&buf[3]==0XAA)    //卡是否支持2.7~3.6V
    			{
    				retry=0XFFFE;
    				do
    				{
    					SendSDCardCmd(SDCard_CMD55,0,0X01);	    //发送SDCard_CMD55
    					r1=SendSDCardCmd(SDCard_CMD41,0x40000000,0X01);//发送SDCard_CMD41
    				}while(r1&&retry--);
    				if(retry&&SendSDCardCmd(SDCard_CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
    				{
    					for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);//得到OCR值
    					if(buf[0]&0x40)SD_Type=SDCard_TYPE_V2HC;    //检查CCS
    					else SD_Type=SDCard_TYPE_V2;   
    				}
    			}
    		}
    	}
    	SDCardCancelCS();       //取消片选
    	if(SD_Type)return 0;  //初始化成功返回0
    	else if(r1)return r1; //返回值错误值	   
    	return 0xaa;          //其他错误
    }
    
    
    /*
    函数功能:读SD卡
    函数参数:
    				buf:数据缓存区
    				sector:扇区
    				cnt:扇区数
    返回值:
    				0,ok;其他,失败.
    说  明:
    				SD卡一个扇区大小512字节
    */
    u8 SDCardReadData(u8*buf,u32 sector,u32 cnt)
    {
    	u8 r1;
    	if(SD_Type!=SDCard_TYPE_V2HC)sector<<=9;//转换为字节地址
    	if(cnt==1)
    	{
    		r1=SendSDCardCmd(SDCard_CMD17,sector,0X01);//读命令
    		if(r1==0)												  //指令发送成功
    		{
    			r1=SDCardRecvData(buf,512);			//接收512个字节	   
    		}
    	}else
    	{
    		r1=SendSDCardCmd(SDCard_CMD18,sector,0X01);//连续读命令
    		do
    		{
    			r1=SDCardRecvData(buf,512);//接收512个字节	 
    			buf+=512;  
    		}while(--cnt && r1==0); 	
    		SendSDCardCmd(SDCard_CMD12,0,0X01);	//发送停止命令
    	}   
    	SDCardCancelCS();//取消片选
    	return r1;//
    }
    
    /*
    函数功能:向SD卡写数据
    函数参数:
    				buf:数据缓存区
    				sector:起始扇区
    				cnt:扇区数
    返回值:
    				0,ok;其他,失败.
    说  明:
    				SD卡一个扇区大小512字节
    */
    u8 SDCardWriteData(u8*buf,u32 sector,u32 cnt)
    {
    	u8 r1;
    	if(SD_Type!=SDCard_TYPE_V2HC)sector *= 512;//转换为字节地址
    	if(cnt==1)
    	{
    		r1=SendSDCardCmd(SDCard_CMD24,sector,0X01);//读命令
    		if(r1==0)//指令发送成功
    		{
    			r1=SDCardSendData(buf,0xFE);//写512个字节	   
    		}
    	}
    	else
    	{
    		if(SD_Type!=SDCard_TYPE_MMC)
    		{
    			SendSDCardCmd(SDCard_CMD55,0,0X01);	
    			SendSDCardCmd(SDCard_CMD23,cnt,0X01);//发送指令	
    		}
     		r1=SendSDCardCmd(SDCard_CMD25,sector,0X01);//连续读命令
    		if(r1==0)
    		{
    			do
    			{
    				r1=SDCardSendData(buf,0xFC);//接收512个字节	 
    				buf+=512;  
    			}while(--cnt && r1==0);
    			r1=SDCardSendData(0,0xFD);//接收512个字节 
    		}
    	}   
    	SDCardCancelCS();//取消片选
    	return r1;//
    }	
    
    

     

     

    展开全文
  • stm32命令规则

    千次阅读 2013-03-05 11:08:54
    STM32 F 103 C 6 T 7 xxx  1 2 3 4 5 6 7 8  第1部分:产品系列名,固定为STM32  第2部分:产品类型;F表示这是Flash产品,目前没有其它选项  第3部分:产品子系列;103表示增强型产品,101表示基本...
    STM32 F 103 C 6 T 7 xxx

       1    2   3   4   5 6 7   8
      第 1 部分:产品系列名,固定为 STM32
      第 2 部分:产品类型; F 表示这是 Flash 产品,目前没有其它选项
      第 3 部分:产品子系列; 103 表示增强型产品, 101 表示基本型产品

    105表示集成一个全速USB 2.0 Host/Device/OTG接口和两个具有先进过滤功能的CAN2.0B控制器,

    107表示在STM32F105系列基础增加一个10/100以太

    网媒体访问控制器(MAC),互联型产品,
      第4部分:管脚数目;
    T=36脚; C=48脚; R=64脚;V=100脚; Z=144
      第5部分:闪存存储器容量:
    6=32K字节; 8=64K字节; B=128K字节; C=256K字节
    D=384K字节; E=512K字节
      第6部分:封装信息;
    H=BGAT=LQFPU=VFQFPN
      第7部分:工作温度范围;
    6=工业级,-40~+85°C
    7=工业级,-40~+105°C
      第8部分:可选项;此部分可以没有,可以用于标示内部固件版本号。

    展开全文
  • Manik的STM32F4xx WS2812B库 描述 STM32F4xx-WS2812B-lib是一个非常易于使用的库,可使用STM32F4xx处理WS2812B可编程LED。 整个库旨在尽可能简单地使用。 它只需要一个命令即可进行初始化,并且只需要一个命令即可...
  • STM32STM32驱动 LCD12864程序代码(串行方式)

    万次阅读 多人点赞 2019-07-30 19:37:34
    STM32 LCD12864 串行通信模式 (从原理让你理解)》 下方代码的实现也是基于上一篇的讲解顺序来的 设备: STM32F407ZGT6 引脚接线: VSS——GND VDD——VCC(5V or 3.3V) V0 亮度调节...

    引言:

    这里我们只讲解接线和代码实现,具体的原理在上一篇博客中已经讲解,如果想了解具体原理可以查看上一篇博客

    《STM32 LCD12864 串行通信模式 (从原理让你理解)》

    下方代码的实现也是基于上一篇的讲解顺序来的     

    设备: STM32F407ZGT6

    引脚接线:

    1.     VSS——GND
    2.      VDD——VCC(5V or 3.3V)
    3.      V0 亮度调节  不接
    4.      CS ——接VCC,持续高电平,一直选通。
    5.      SID ——接PE1
    6.      SCLK  ——接PE0
    7.      PSB——接GND  串行模式  或者飞线与1脚相连
    8.      BLA——VCC(5V or 3.3V)   或者飞线与2脚相连
    9.      BLK——接GND                 或者飞线与1脚相连
    10.               剩余引脚不接,留空

       

    这样我们最少只会用到4根线  VCC电源 GND地线  SID串行输入  SCLK  时钟  便可以实现串行通信

    代码实现:

    LCD写入一个字节:

     

    #define WRITE_CMD	0xF8//写命令  
    #define WRITE_DAT	0xFA//写数据
    
    /*! 
    *  @brief      LCD串行发送一个字节
     *  @since      v1.0
     *  @param  byte   写入字节
     *  @author     Z小旋
     */
    void SendByte(u8 byte)
    {
         u8 i; 
    	  for(i = 0;i < 8;i++)
        {
            if((byte << i) & 0x80)  //0x80(1000 0000)  只会保留最高位
    		{
    		    SID = 1;           // 引脚输出高电平,代表发送1
    		}
    		else
    		{
    			SID = 0;         // 引脚输出低电平,代表发送0
    		}
    		/*或		
    		SID =	(Dbyte << i) & 0x80;
    				
    		上面那样为了方便理解
    		*/
    		SCLK = 0;   //时钟线置低  允许SID变化
    		delay_us(5); //延时使数据写入
    		SCLK = 1;    //拉高时钟,让从机读SID
    	}   
    }
    
    /*! 
     *  @brief      LCD写指令
     *  @since      v1.0
     *  @param  Cmd   要写入的指令
     *  @author     Z小旋
     */
    void Lcd_WriteCmd(u8 Cmd )
    {
         delay_ms(1);    //由于我们没有写LCD正忙的检测,所以直接延时1ms,使每次写入数据或指令间隔大于1ms 便可不用写忙状态检测
         SendByte(WRITE_CMD);            //11111,RW(0),RS(0),0   
         SendByte(0xf0&Cmd);      //高四位
         SendByte(Cmd<<4);   //低四位(先执行<<)
    }
    
    /*! 
     *  @brief      LCD写数据
     *  @since      v1.0
     *  @param  Dat   要写入的数据
     *  @author     Z小旋
     */
    void Lcd_WriteData(u8 Dat )
    {
         delay_ms(1);     //由于我们没有写LCD正忙的检测,所以直接延时1ms,使每次写入数据或指令间隔大于1ms 便可不用写忙状态检测
         SendByte(WRITE_DAT);            //11111,RW(0),RS(1),0
         SendByte(0xf0&Dat);      //高四位
         SendByte(Dat<<4);   //低四位(先执行<<)
    }

    向LCD发送一个字节,也就是SID引脚相对于高低电平 高电平=1 低电平=0  同时时钟线变化,使得数据可以读取和发送

    结合第一篇原理介绍即可理解。

    关于&运算与<<  参看  《C语言运算符与操作符的用法全面汇总(非常有用)》

     

    LCD初始化:

    这里为了方便移植,将GPIO的初始化与LCD初始化分为两个,使用时根据自己的引脚只修改GPIO初始化即可

    宏定义和GPIO初始化:

    
    #define WRITE_CMD	0xF8//写命令  
    #define WRITE_DAT	0xFA//写数据
    
    //接口(SID: PE1  SCLK: PE0) 
    #define SID PEout(1)
    #define SCLK PEout(0)
    
    
    /*! 
    *  @brief      GPIO_init
     *  @since      v1.0
     *  @param  None
     *  @author     Z小旋
     *  使用时自行修改这里的初始化即可
     */
    void lcd_GPIO_init()
    {
           
      GPIO_InitTypeDef  GPIO_InitStructure;
    
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOE时钟
    
      //GPIOE0,E1初始化设置
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
      GPIO_InitStructure.GPIO_PuPd =  GPIO_PuPd_NOPULL;//无上拉
      GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化
      SID=1;
      SCLK=1;
    }

    根据不同的型号和管脚修改对应初始化即可

    LCD初始化:

    /*! 
     *  @brief      LCD初始化
     *  @since      v1.0
     *  @param  None
     *  @author     Z小旋
     */
    void Lcd_Init(void)
    { 
        delay_ms(50);   	//等待液晶自检(延时>40ms)
    	Lcd_WriteCmd(0x30);        //功能设定:选择基本指令集  ,选择8bit数据流
        delay_ms(1);//延时>137us 
        Lcd_WriteCmd(0x0c);        //开显示
        delay_ms(1);	//延时>100us
        Lcd_WriteCmd(0x01);        //清除显示,并且设定地址指针为00H
        delay_ms(30);	//延时>10ms
    	Lcd_WriteCmd(0x06);        //每次地址自动+1,初始化完成
    }
    

    LCD写入字符或汉字:

    /* 字符显示RAM地址    4行8列 */
    uint8_t LCD_addr[4][8]={
    	{0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87},  		//第一行
    	{0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97},		//第二行
    	{0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F},		//第三行
    	{0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F}		//第四行
    	};
    
    /*! 
     *  @brief      显示字符或汉字
     *  @since      v1.0
     *  @param  x: row(0~3)
     *  @param  y: line(0~7) 
     *  @param 	str: 要显示的字符或汉字
     *  @author     Z小旋
     */
    void LCD_Display_Words(uint8_t x,uint8_t y,uint8_t*str)
    { 
    	Lcd_WriteCmd(LCD_addr[x][y]); //写初始光标位置
    	while(*str>0)
        { 
          Lcd_WriteData(*str);    //写数据
          str++;     
        }
    }

    首先写DDRAM对应初始游标位置,然后在该位置写入字符串 写一个字节之后,DDRAM对应游标地址就自动+1到下一个游标位置继续写,直到字符串空为止

    LCD清屏:

    /*! 
     *  @brief      清屏函数
     *  @since      v1.0
     *  @param  None
     *  @author     Z小旋
     */
    void LCD_Clear(void)
    	{
    		Lcd_WriteCmd(0x01);			//清屏指令
    		delay_ms(2);				//延时以待液晶稳定【至少1.6ms】
    	}
    	

    LCD显示图片:

    /*! 
     *  @brief      显示图片
     *  @since      v1.0
     *  @param  *pic   图片地址
     *  @author   
     */
    void LCD_Display_Picture(uint8_t *img)
    	{
    		uint8_t x,y,i;
    		Lcd_WriteCmd(0x34);		//切换到扩充指令
    		Lcd_WriteCmd(0x34);		//关闭图形显示
    		for(i = 0; i < 1; i++)   //上下屏写入
    		{
    			for(y=0;y<32;y++)   //垂直Y写32次
    			{  
    				for(x=0;x<8;x++)   //横向X写8次
    				{
    					Lcd_WriteCmd(0x80 + y);		//行地址
    					Lcd_WriteCmd(0x80 + x+i);		//列地址
    					Lcd_WriteData(*img ++);		//写高位字节数据 D15-D8   
    					Lcd_WriteData(*img ++);		//写低位字节数据 D7-D0
    				}
    			}
    		}
    		Lcd_WriteCmd(0x36);//打开图形显示		
    		Lcd_WriteCmd(0x30);        //切换回基本指令
    	}	

    具体原理可以结合 LCD图片显示 部分查看

    这里要注意  在显示一幅图片之后,要加上2s左右延时,否则不会有图片显示

    这里再把显示步骤放在下面,方便理解

    图片显示的步骤

    1切换到扩充指令
    2 关闭绘图显示功能


    3 先将垂直的坐标(Y)写入CGRAM地址
    4 再将水平的位元组坐标(X)写入CGRAM地址
    5 将高位字节D15-D8写入RAM中
    6 将低位字节D7-D0写入到RAM中

    重复3-6步,完成图片各个部分的写入  先写上半屏,再写下半屏

    7 打开绘图显示功能                                                                                                                                                                          8切换回基本指令

    使用图片取模软件时要注意 图片取模方式:横向取模,字节正序

    到此基本的功能都已经实现了,我把完整的工程代码放到下面,有需要的可以自行下载查看

    弄到百度云了,CSDN下载还要钱。。。

    链接: https://pan.baidu.com/s/1_OabL-e2mgZebKjjFnW1Ow 提取码: tfxw 

    github:    https://github.com/ZXiaoxuan/STM32-LCD12864/tree/ZXiaoxuan

    至此,LCD12864完毕,

    PS: 代码没有任何问题,直接修改GPIO初始化部分即可,如果亮不了,先自行检查,还有查看评论区,看下自己是否有相同问题(供电,接线,F1与F4GPIO初始化不同...等等),不行就在评论区留言,我看到都会回复帮您解决

    展开全文
  • STM32 AT命令详细命令补充

    千次阅读 2014-07-02 11:06:07
    AT+CBST 选择数据传输的类型 选择模式 AT+FCLASS 选择发送数据or 传真 服务报告控制 AT+CR 是否报告提供服务 结果代码 AT+CRC 报告不同的结果...
  • STM32 AT命令的学习

    千次阅读 2014-07-02 10:45:13
    //STM32 基本命令集 //------------------------------------------------------------------ const romchar AT_AT[] = {"AT\r\n"}; const romchar AT_CBC[] ={"AT+CBC\r\n"}; //检查充电状态,以及电池电量占...
  • STM32开发 -- Jlink常用命令

    千次阅读 2019-06-18 18:58:11
    device = STM32F429ZI erase loadbin BOOT.bin 0x8000000 loadbin 正式版本.bin 0x08004000 loadbin 工厂测试.bin 0x08020000 savebin 工厂生产.bin 0x08000000 0x00080000 rx 3 qc exit 一直在用这个...
  • STM32F4-core-for-STM32-Arduino 这是此处托管的 Roger Clark STM32 Arduino 项目的 STM32F4 内核的克隆: : 该存储库包括对 spi.c、spi.h、rccF2.h 和 rccF2.c 的更改,以便在 16 位 48KHz 菲利普斯标准模式下...
  • 第81章 STM32H7的QSPI 总线应用之QSPI Flash的STM32CubeProg下载算法制作 本章节为大家讲解STM32CubeProg下载算法制作方法。 81.1 初学者重要提示 81.2 STM32CubeProg简介 80.3 STM32CubeProg下载算法基础知识 ...
  • 第85章 STM32H7的SPI 总线应用之SPI Flash的STM32CubeProg下载算法制作 本章节为大家讲解STM32CubeProg下载算法制作方法。 85.1 初学者重要提示 85.2 STM32CubeProg简介 85.3 STM32CubeProg下载算法基础知识 ...
  • STM32F103平台下的VS1053b MIDI驱动。包含C语言源文件和头文件。 1、MIDI模块是单向串口通信,波特率为31250;还要用到一个Reset脚。程序中默认使用STM32F103的UART3的两个引脚(TX=MIDI,RX=RESET)。 2、源文件...
  • STM32开发 -- md5sum命令

    千次阅读 2020-03-16 15:08:49
    参看:md5sum命令 md5sum命令采用MD5报文摘要算法(128位)计算和检查文件的校验和。一般来说,安装了Linux后,就会有md5sum这个工具,直接在命令行终端直接运行。 MD5算法常常被用来验证网络文件传输的完整性,防止...
  • STM32驱动1602显示模块简介硬件LCD1602引脚定义配置方法1 在.h文件中定义引脚和数据方向2 对GPIO初始化(E,RW,CS)3 读1602状态4 写1602命令5 写1602数据6 1602初始化7 编写主函数1. 定义一个要显示的数组2. 初始化...
  • STM32开发项目:如何从TRUEStudio转移到STM32CubeIDE 以 Ubuntu 18.04 的TRUEStudio(版本号:9.1)转移至macOS STM32CubeIDE(版本号:1.3.0)为例 Clean原TrueStudio工程(Project->Clean) 删除原True...
  • Mac开发STM32之调试工具 一、相关名词解释 JTAG与SWD JTAG是一种国际标准测试协议,主要用于芯片内部测试、调试和在线编程 SWD与JTAG 是常用的ARM芯片仿真调试方式。SWD相较于JTAG,使用接口更少、高速下也更稳定,...
  • arduino 操作stm32

    2020-04-21 15:55:42
    将Arduino_STM32放到arduino\hardware目录下面, 添加开发板 向STM32烧写Bootloader,把boot0插到1的位置,boot1插到0的位置。然后插入你的串口下载线(C8T6,这个片子的Tx和Rx分别对应引脚PA9和PA10) CD...
  • 基于STM32设计的遥控小车(手机APP+GPS+温湿度+ESP8266)

    万次阅读 多人点赞 2021-06-11 00:33:42
    小车主控MCU: STM32F103ZET6 STM32程序开发IDE: keil5 STM32程序风格: 采用寄存器方式开发,注释齐全,执行效率高,方便移植 手机APP: 采用QT设计,程序支持跨平台编译运行(Android、IOS、Windows、Linux都可以...
  • STM32 & Clion

    千次阅读 2017-12-10 11:50:41
    在Clion中开发STM32
  • 本次更新内容为STM32CubeMX生成STM32H7 工程项目应用中Pinout&Configuration关于Timer 和Connectivity部分说明,文中Tips是比较易出错的点,多多关注。欢迎关注本公众“硬件开发不完全攻略”,上传可能中可能...
  • 接着上一篇上传,这个是STM32配置CH375B时用到的接口函数 代码如下: #include "bsp_ch375.h" #include "bsp_init.h" #include "bsp_delay.h" void Bsp_CH375_Write_Cmd(uint8_t cmd ) /* 向CH375的命令端口写入...
  • STM32工程

    千次阅读 2015-12-09 23:31:02
    在LINUX下开始一个STM32工程在LINUX下开始一个STM32工程 一安装工具 二 如何工作 1 需要作的工作 2 工作分析 21 makefile分析 22 链接器脚本分析 3 分析结果 三开始工作 1 创建文工程目录 3 编写Makefile 32 src子...
  • 首先在windows的CMD命令管理器中安装pyserial,直接在CMD中键入如下字符pip install pyserial再将Stm32用USB连接到电脑,打开设备管理器显示端口为COM14,然后在python中写下import serial#连接串口serial = s...
  • stm32串口代码详解

    2019-11-07 15:00:22
    stm32串口
  • 建立STM32工程模板(STM32F103ZET6为例)

    千次阅读 2017-05-06 15:37:43
    从ST的官方网站获取的STM32最新固件库v3.5里包含的内容如下: 解压的文件夹名为:STM32F10x_StdPeriph_Lib_V3.5.0,里面包含了4个文件夹,一个网络链接,和一个ST库开发助手。 1. Project 文件夹 1.1 Example:...
  • STM32启动过程分析

    千次阅读 2021-06-05 14:49:32
    在讲解 STM32 启动过程之前,我们先来了解一下 STM32 的程序和数据在 Flash 和 SRAM 上到底是如何存储的,因为有了这方面的知识之后,非常有助于我们理解 STM32 启动过程中还做了哪些隐藏的工作。关于详细的程序和...
  • 想要在1602液晶显示上显示...I LOVE STM32 ///**********************************// 如何使用STM32 来实现呢? 首先看看LCD1602的重要知识点: 引脚功能说明 1602LCD采用标准的14脚(无背光)或16脚(带背...
  • stm32遥控时钟

    2019-07-04 15:03:22
    本次设计为STM32初学成品,基于STM32F103ZET6的红外遥控电子时钟,采用了战舰开发板配套的TFTLCD显示屏,红外遥控器HS0038等硬件,实现了当前日期时间的实时显示(RTC),遥控控制日期时间的更改,闹钟的设置,响铃...
  • git clone https://github.com/h5b/stm32F429.git cd stm32F429 git submodule init git submodule update vagrant up 这样就搭建了一个基于 Ubuntu 12.04 的虚拟开发机主机stm32-dev 。 已安装最新的 GCC ARM ...
  • (1) STM32CubeMX:STM32CubeMX是一个配置STM32代码的工具,用于生成带makefile的HAL库工程。注意STM32CubeMX是依赖Java的,所以要确保你电脑上安装了JRE。 (2) VSCode:超好用的编辑器,支持Windows、Linux、Mac,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,395
精华内容 2,958
关键字:

b命令stm32