ILI9431的LCD屏使用,STM32F1控制
之前看到了公众号大佬法的应该学着写点技术博客,再加上搞这个屏幕的时候网上没有找到成套的教程,所以写下了这个博客,请多指教。(STM32F103RCT6,测试时使用的是正点原子的mini开发板,其实用谁的开发版并不重要)
目录
一、模块的使用
二、编写驱动
三、显示图片
一、模块的使用
最近在做毕设,想用一块大一点的屏幕,最后挑了这款ips屏,ili9431驱动,模块出厂40pin。(具体某宝哪家买的就不说了)
测试屏幕时我买了转接板,方便测试。
厂家给出的引脚图是这样的(手册中的详细描述略)
显然 ,6 7 脚是供电脚,接上3.3V ;5脚GND
9脚cs 是片选脚,低电平有效 ;10脚RS/SPI SCL/SCK 使用SPI的时候是时钟线 SCK;
11脚WR/A0 换了个说法,其实就是CMD/DATA引脚(命令/数据)引脚 ;12脚RD读控制脚
13脚 是串口数据的输入信号,接stm32的MOSI(单片机是主机往从机发);同理,14脚接单片机MISO
15屏复位脚 常见说法就是RST;
33脚A,34-36脚K,分别是背光的正极和负极,这两个一个接3.3,一个接地,屏幕才能亮起来,否则哪怕显示出来了,你得打折强光手电才看到的。
我们用4线spi,所以IM0 IM1 IM2 分别接地,3.3,3.3 ;
以上就是屏幕正常工作,必须要使用的引脚,其余的按手册上处理(要么接地 要么悬空即可).
引脚资源分配如下
RST(复位) | PC1 |
DC/A0(命令/数据) | PC2 |
CS(片选) | PC3 |
BLK(背光控制) (就是上面的K引脚) | PB9 |
Spi_sck | PA5 |
Spi_miso | PA6 |
Spi_mosi | PA7 |
PA5 6 7 均为复用,注意配置 |
显示屏模块电路
二、编写驱动
到csdn上下载了一个别人写好了的驱动,那位老哥的驱动只有驱动文件,具体单片机实现留好了接口,十分感谢,但是文件上没有具体写作者是哪位,太可惜了。
函数里对于引脚的操作通过宏定义进行了一次封装,如果单片机不是stm32 只需修改为自己对应的引脚操作函数即可。
屏幕的初始化,大致是: 初始化引脚(GPIO,SPI),初始化外设 ,然后就可以调用函数看看效果了
void SPI1_idev_Init(void)
{ SPI_InitTypeDef SPI_InitStructure;SPI1_IO_Init();RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );//SPI1时钟使能 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为High电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第2个跳变沿(上升或下降)数据被采样SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为,SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器//DMA_SPI1_idev_init(); //配置SPI1的DMA功能SPI_Cmd(SPI1, ENABLE); //使能SPI外设
}
//csdn上卸载的驱动这个函数只留了接口,所以我们把内容填上
void ILI9341_io_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 |GPIO_Pin_2 |GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_SetBits(GPIOC, GPIO_Pin_1 |GPIO_Pin_2 |GPIO_Pin_3); RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 ;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_ResetBits(GPIOB, GPIO_Pin_9 ); }
//初始化外设
void SPI1_idev_Init(void)
{ SPI_InitTypeDef SPI_InitStructure;SPI1_IO_Init();RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );//SPI1时钟使能 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为High电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第2个跳变沿(上升或下降)数据被采样SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为,SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器//DMA_SPI1_idev_init(); //配置SPI1的DMA功能SPI_Cmd(SPI1, ENABLE); //使能SPI外设
}
//初始化外设
void SPI1_idev_Init(void)
{ SPI_InitTypeDef SPI_InitStructure;SPI1_IO_Init();RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );//SPI1时钟使能 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPISPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为High电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第2个跳变沿(上升或下降)数据被采样SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为,SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器//DMA_SPI1_idev_init(); //配置SPI1的DMA功能SPI_Cmd(SPI1, ENABLE); //使能SPI外设
}
然后就可以开始愉快的调用了;
调用发现,屏幕上想要显示字符的部分是一个黑色马赛克,并未成功,所以我硬着头皮debug,屏幕显示的基本原理就是画点
通过debug发现,原作者的函数中,画笔的颜色和当前背景颜色是通过lcddev中的cur_brushcl ,cur_backcl两个成员来表示的,在调用函数前对这两个变量没有赋值,所以程序出了bug。经过多重考虑,我把这两个变量直接写死,反正我只需要白底黑字;
void LCD_ShowChar(unsigned short int x,unsigned short int y,unsigned char ch,unsigned char csize,unsigned char mode)
{unsigned char temp,t1,t;unsigned short int y0=y;unsigned char sz=(csize/8+((csize%8)?1:0))*(csize/2); //得到字体一个字符对应点阵集所占的字节数ch=ch-' ';//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)for(t=0;t<sz;t++){ if(csize==12)temp=ascii_1206[ch][t]; //调用1206字体else if(csize==16)temp=ascii_1608[ch][t]; //调用1608字体else if(csize==24)temp=ascii_2412[ch][t]; //调用2412字体else return; //没有的字库for(t1=0;t1<8;t1++){ if(temp&0x80){LCD_DrawPoint_Color(x,y,BLACK);//lcddev.cur_brushcl;我这里直接写成了黑色}else if(mode==0){LCD_DrawPoint_Color(x,y,WHITE);//lcddev.cur_backcl;写死,白色} temp<<=1;y++;if(y>=lcddev.height)return; //超区域了if((y-y0)==csize){y=y0;x++;if(x>=lcddev.width)return; //超区域了break;}} }
}
三、显示图片
对于这类屏幕要想显示图片,肯定得先取模,经过调查,取模应该采用水平扫描,不带数据头,16位彩色格式进行取模
取模后获得数据(上图仅为展示注意参数),我实际上取模了一个320*240的图片,16位rgb格式的话这个对存储空间的需求还是很大的,所以测试成功一次后,我加了一个宏定义,需要的时候才编译进去,缩短每次下载时间。(我用的dap下载器,文件大了就很慢)
使用网上老哥提供的函数进行调用
/*************************************************************************************
* 名 称:void LCD_DrawPicture(unsigned short int StartX,unsigned short int StartY,unsigned short int PicXend,unsigned short int PicYend,const unsigned char *pic)
* 功 能:在指定座标范围显示一副图片
* 入口参数:StartX 行起始座标
* StartY 列起始座标
* PicXend 图片的X像素
* PicYend 图片的Y像素pic 图片头指针
* 出口参数:无
* 说 明:图片取模格式为水平扫描,16位颜色模式
*LCD_DrawPicture(0,0,320,240,gImage_logo);
*************************************************************************************/
void LCD_DrawPicture(unsigned short int StartX,unsigned short int StartY,unsigned short int PicXend,unsigned short int PicYend,const unsigned char *pic)
{unsigned long j=0; unsigned char *pdata = (unsigned char *)pic;LCD_set_windows(StartX,StartY,StartX+PicXend-1,StartY+PicYend-1); //设置显示窗口for(j=0;j<PicXend*PicYend;j++) //向窗口中填入内容,即图片的模值{LCD_wt8bitData(pdata[j*2+1]);LCD_wt8bitData(pdata[j*2]);}
}
最终开机logo效果图。(事实上,一是可以用字符串显示代替,二也可以拆分成三个图片分别在屏幕上不同位置显示,这样可以缩小数据大小,你看,图像中白色部分那么多,浪费了存储空间)
你还别说这ips屏还挺好用,其实也没比那个一点几寸的oled单色屏幕贵多少。
模块到这里测试就结束了,工程、代码我会上传。
后续我会把驱动进行一个移植,因为我的项目想用cubemx (HAL库)做,并且有freertos操作系统。
第一次写博客,语言也不专业,欢迎大家批评指正。
ILI9431的LCD屏使用,STM32F1控制相关推荐
- python编程lcd显示_PyQt5快速上手基础篇2-按钮控制LCD屏显示
前言 上一节我们完成了PyQt5开发环境搭建,本节开始我们正式进入PyQt5的世界,首先我给大家介绍下QT的信号与槽,然后利用这一特点完成点击按钮触发LCD屏显示功能. 一.基础知识 1. PyQt5 ...
- LCD屏参:手把手教你计算LCD屏参(proch值)
LCD屏参(proch值)解释和计算 Linux内核的lcd控制器使用clcd_panel结构体表示一个LCD屏的硬件参数: /* include/linux/fb.h */ struct fb_ ...
- rust怎么调整夜晚亮度_买手机时LCD屏和OLED屏怎么选?终于明白了!
手机近几年来更新的速度越发的快,屏幕色彩的艳丽程度也越来越绚丽.目前最为主流的LCD屏和OLED屏,这两款屏幕都有什么优缺点,比较一下做一个明了. 苹果最新的iPhone11系列新机中,iPhone1 ...
- mipi接口 1280(RGB)*720 LCD屏开发驱动笔记帖
ps:创业开发产品,自学笔记,不一定适合教材性的阅读,零碎整理,自我总结用 材料:4.1寸lcd屏两块,屏自带触控,屏幕资料具备,rk3399和MK8788开发版上分别开发. 开发环境: 1]rk33 ...
- 简单了解一下LCD屏工作原理
谈及LCD屏,想必绝大多数人都耳熟能详,现实中运用到LCD屏的地方还是有很多的.例如家用电视显示屏,电子秤显示屏,手机显示屏等. 知道LCD屏这个名词的人居多,但是真正了解其工作原理的,应该还不是很多 ...
- QSPI驱动带NV3030B的LCD屏
(说明:本文没有详细描写有关QSPI通信时的细节,只是作为一个简要记录,说明一下QSPI驱动屏幕时的一些要点) 1.引脚说明: (1)LED_K:LCD屏背光负极 (2)LED_A:LCD屏背光正极 ...
- lcd屏和amoled屏的优缺点 lcd屏和amoled屏哪个效果好
LCD和AMOLED各有优缺点,而且随着LCD技术的不断优化和AMOLED技术的不断完善,在一些中高端手机上,LCD和AMOLED之间的差距已经非常小了,不足以对日常使用构成巨大影响. 选lcd屏还是 ...
- STM32 FSMC接口驱动4.3寸TFT LCD屏
STM32 FSMC接口驱动4.3寸TFT LCD屏 STM32的FSMC接口是并行总线接口,可以用于驱动存储芯片如FLASH/SRAM等,也可以用于驱动并口LCD屏. 这里以STM32F103VET ...
- LCD屏应用--笔记
当前主流的显示器件 1.LED大屏幕 主要应用在大型的商场,也是由一块块的小型的屏幕拼接到一起的,背面会比较厚 在工作过程中会产生大量的热,有些LED后边会有一个空调 专门用来散热. 2.数码管 5 ...
- 屏幕篇—如何最快速驱动LCD屏
屏幕篇-如何最快速驱动LCD屏 前言 LCD屏的驱动对于新手来说,这是一个很大的拦路虎.学完基础外设后,在这里就不知道怎么下手了.一个完整的LCD驱动包含的内容是非常多的,最基础的描点,画线,显示字符 ...
最新文章
- python读取html内容 dom获取_python学习笔记十三 JS,Dom(进阶篇)
- 独家 | 一文读懂随机森林的解释和实现(附python代码)
- 2012年度最受欢迎中国开源软件评选
- # 20180908 2018-2019-2 《密码与安全新技术专题》第9周作业
- qt5中服务器文件传输,POST在Qt5中发送JSON文件的请求
- 自锁时间电路plc_PLC对两台三相交流电动机联锁启停控制
- Docker学习总结(52)—— Docker容器环境变量相关知识点的总结
- dojo/dom-class源码学习
- 2021美赛MCM选题
- 水系图一般在哪里找得到_进展 | 水系钾离子电池研究取得重要进展
- 华为薪酬体系的整体框架
- 车型代号对照表_车型和VIN代号对照表3.24.doc
- java实现png转ico,支持尺寸选择
- 倍福--本地电脑配置EtherCAT网卡
- buu-[WUSTCTF2020]level3
- Mac安装sshpass
- 计算机职称落户,人才引进落户等6类落户方式 新政策全部在这里
- 射影几何 -- 平面射影几何 1
- java从入门到精通二十四(三层架构完成增删改查)
- Vulkan免费版VulkanRT 1.0.65.0
热门文章
- HTML+CSS期末网页课设——游戏宣传网页(全部源码)
- 固定在计算机主机箱体上的起到连接计算机,固定在计算机主机箱箱体上的、起到连接计算机各种部件的纽带和桥梁作用的是( )。...
- Java多线程--概述-转自林炳文Evankaka
- SpringBoot线程池获取service实例空指针
- 4200: [Noi2015]小园丁与老司机
- 《实用python程序设计》练习题:向量点积计算
- 第二章课后习题 华氏温度与摄氏温度的java简单转换
- QT入门第四天消息盒子+对话框+定时器+日期和时间(源码)
- 数格子算面积的方法_数格子估算面积与数格点估算面积
- awflasher的Vplayer 2.1 ( FLV Player )