数码之家

 找回密码
 立即注册
搜索
查看: 2843|回复: 8

STC8H单片机(开天斧实验板)硬件SPI驱动ILI9481-3线SPI总线TFT彩屏

[复制链接]
发表于 2023-2-28 11:51:34 | 显示全部楼层 |阅读模式
本帖最后由 慕名而来 于 2023-2-28 11:51 编辑

上个月发了几篇有关STC的屠龙刀实验板驱动7”并口TFT屏的应用文章,链接如下:
STC屠龙刀实验板驱动7寸TFT屏测试代码分享1-LCM接口驱动
https://www.mydigit.cn/forum.php?mod=viewthread&tid=363836&fromuid=1505079
STC屠龙刀实验板驱动7寸TFT屏测试代码分享2-DMA_LCM接口应用
https://www.mydigit.cn/forum.php?mod=viewthread&tid=363971&fromuid=1505079
STC屠龙刀实验板驱动7寸TFT屏测试代码分享3-片内RTC时钟演示
https://www.mydigit.cn/forum.php?mod=viewthread&tid=364135&fromuid=1505079

经坛友 @疯狂的兔子来了 帮忙申请的STC厂家赠送的板子拢共有两块,除了上述的“屠龙刀”-STCG32实验板外还有一块——“开天斧”-STC8H8K64U实验板,前几天在STC社区分享了一篇基于开天斧实验板驱动三线SPI串口TFT屏的文字,今天得闲重新整理后分享于此,有兴趣的新手可以看看,高手直接无视算了。
手里有一个三线SPI驱动的ILI9841的TFT屏,当时入手是只考虑到了SPI总线驱动却没想到还有这种缺少指令/数据控制引脚的总线模式,入手后通过I/O模拟时序也可以点亮并且还曾经在此发帖分享过代码:初次使用STC8H4KTL单片机驱动SPI接口TFT屏https://www.mydigit.cn/forum.php?mod=viewthread&tid=330205&fromuid=1505079
为了测试开天斧板的硬件SPI功能又找来这个TFT模块来编程控制并分享相关资料与代码。
一、屏幕资料摘录:




二、ILI9481相关时序:



三、STC8H单片机硬件SPI程序:程序中已经做了详细注释、有错漏、疑问之处可以跟帖交流

#include <STC8_spi.h>
//====硬件SPI初始化函数=========================
//SPCTL=0xDC,0xDD,0xDE,0xDF;分别对应1/4,1/8,1/16,1/2分频
//此屏硬件SPI驱动时下设置22.1184MHz时钟刷屏时间约2.5s
void spi_init()
{
    P_SW1|=1<<2;  //使用SPI通道2时需要切换引脚
    SPDAT = 0;   //清空数据寄存器
    SPSTAT = 0xC0;  //清除所有标志(共两个)
    SPCTL = 0xDF; //忽略SS-使能SPI-高位先行-主机模式-时钟空闲时为高、上升沿(第二个边沿)采样
}
//====硬件SPI发送一个字节函数==============
//查询方式
void SPI_WriteByte(unsigned char temp)
{
    SPDAT = temp;   //待发送数据存入数据寄存器
    while(!(SPSTAT & 0x80));//等待传输完成SPIF=0
    SPSTAT = 0xC0;   //传输完成后置SPIF=1、WCOL=1清除标志
}
//==============写指令函数======================
void write_command(uchar comd)
{
    cs=0;
    SPI_WriteByte(comd>>1);  //发送DC加数据的前7位
    SPI_WriteByte(comd<<7);  //发送数据的最低位
    cs=1;
}
//===============写8位数据函数==================
void write_data(uchar dat)
{
    cs=0;
    SPI_WriteByte((dat>>1)|(0x80));  //发送DC加数据的前7位
    SPI_WriteByte(dat<<7);    //发送数据的最低位
    cs=1;
}


四、刷屏底层代码:
//====写18位颜色数据函数===============
//18bpp Frame Memory Write模式、RGB三色各6位数据写入3个8位寄存器中、高位对齐忽略低2位
//RGB565-16位色值经过对R、B插值变成RGB666-18位色值后分别写入显存
void LCD_WR_DATA(u16 da)
{
    write_data(((da>>8)&0xf8)|0x04);  //将R值移动到低8位、取出5位色值再插入1位色值
    write_data((da>>3)&0xFC);   //将G值移动到低8位、取出6位色值
    write_data((da<<3)|0x04);   //将B值移动到高位对齐、再插入1位色值
}

五、工程代码分享:



六、显示效果:



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

打赏

参与人数 1家元 +100 收起 理由
家睦 + 100

查看全部打赏

发表于 2023-2-28 18:38:50 来自手机浏览器 | 显示全部楼层
老哥能不能把8025给这个板子适配一下?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-3-1 11:52:39 | 显示全部楼层
本帖最后由 慕名而来 于 2023-3-1 12:12 编辑
触景情伤 发表于 2023-2-28 18:38
老哥能不能把8025给这个板子适配一下?

开天斧板子使用RX8025T是没问题的,只要启用它的硬件I2C总线挂载8025就可以了,另外,还有一个简易方案,这个芯片也有自带的RTC实时时钟,也可以读年月日时分秒数据,只是受限与内部振荡器精度或者外接32K晶振的热稳定性而精度不易弄的太好,咱们可以利用8025做STC8的外部时钟源(做晶振用),此时8025不用连接通讯线路,只需要将8025的pin3-FOUT引脚连接到板上J2端子的pin3焊盘(P1.7)的XTALI时钟输入引脚上就可以了(此时STC8的P1.6脚空闲也不能用于其他控制了),开天斧板子设置RTC功能时设置为使用外部时钟即可,另外它的寄存器数据是HEX码,无需进行数据转换这是很人性化的设计,这个方案我曾经用STC8H8K64TL验证过,如果你利用这个方案的话可以先试试,如果编程有问题咱们再交流解决。
一、接线图如下:






二、下面是STC8H的RTC初始化函数供参考:

//----RTC初始化函数------------------------------------------------
//YEAR、MONTH、DAY、HOUR、MIN、SEC 这些变量名称已在头文件中定义了可以直接使用
//需要注意的是不同的STC8头文件中的变量拼写或有不同应以自己使用的头文件为准。
void RTC_config(void)
{
X32KCR = 0xc0; //启动外部 32K 晶振
while (!(X32KCR & 0x01)); //等待时钟稳定
RTCCFG &= ~0x02; //选择外部 32K时钟 作为 RTC 时钟源

    RTCCFG |= 0x01; //触发 RTC 寄存器初始化
    RTCIF = 0; //清中断标志
    RTCIEN = 0x08; //使能 RTC 秒中断
    RTCCR = 0x01; // RTC 使能
}
//----RTC秒中断函数---------------------------------------------------
void RTC_Isr() interrupt 36
{
    if(RTCIF & 0x08) //判断是否秒中断
    {
        RTCIF &= ~0x08; //清除中断标志
        B1S_Flag = 1;
    }
}
//====分别读取时间数据============================
void read_RTCdata()
{
    ye=YEAR;
    mo=MONTH;
    da=DAY;
    hi=HOUR;
    mi=MIN;
    si=SEC;
}
//====写入STC8H单片机RTC寄存器数据函数==========================
void write_RTC(u8 *timedata)
{
    INIYEAR  = timedata[0];
    INIMONTH = timedata[1];
    INIDAY   = timedata[2];
    INIHOUR  = timedata[3];
    INIMIN   = timedata[4];
    INISEC   = timedata[5];
    INISSEC  = timedata[6];
}
//====RTC数据更新函数=========================
//将调整后的时间数据写入RTC寄存器中
void RTC_Data_Update()
{
    time[0]=ye;
    time[1]=mo;
    time[2]=da;
    time[3]=hi;
    time[4]=mi;
    time[5]=0;
    time[6]=0;
    write_RTC(&time);
    RTCCFG |= 0x01; //触发 RTC 寄存器初始化
}

三、下面是不使用STC8H内部RTC而是使用I2C通讯驱动8025的相关代码:
//------I2C.c-----------------
bit busy;
//------------------------------------------
void I2C_init()
{
    I2C_USE_P15P14();//I2C端口引脚P1.5/P1.4
    I2CCFG = 0xE0; //使能 I2C 主机模式
    I2CMSST = 0x00;
}
//------------------------------------------
void Start()
{
    busy = 1;
    I2CMSCR = 0x81; //发送 START 命令
    while (busy);
}
//------------------------------------------
void SendData(char dat)
{
    I2CTXD = dat; //写数据到数据缓冲区
    busy = 1;
    I2CMSCR = 0x82; //发送 SEND 命令
    while (busy);
}
//------------------------------------------
void RecvACK()
{
    busy = 1;
    I2CMSCR = 0x83; //发送读 ACK 命令
    while (busy);
}
//------------------------------------------
char RecvData()
{
    busy = 1;
    I2CMSCR = 0x84; //发送 RECV 命令
    while (busy);
    return I2CRXD;
}
//------------------------------------------
void SendACK()
{
    I2CMSST = 0x00; //设置 ACK 信号
    busy = 1;
    I2CMSCR = 0x85; //发送 ACK 命令
    while (busy);
}
//------------------------------------------
void SendNAK()
{
    I2CMSST = 0x01; //设置 NAK 信号
    busy = 1;
    I2CMSCR = 0x85; //发送 ACK 命令
    while (busy);
}
//------------------------------------------
void Stop()
{
    busy = 1;
    I2CMSCR = 0x86; //发送 STOP 命令
    while (busy);
}

四、下面是RX8025T的底层驱动函数:
//----在指定寄存器中写入一个数据------------------
void write_8025(u8 addr,u8 date)//(地址,数据)
{
    Start();
    SendData(0x64);
    RecvACK();
    SendData(addr);
    RecvACK();
    SendData(date);
    RecvACK();
    Stop();
}
//----在指定寄存器中读出一个数据------------------
//专用于中断函数调用
u8 read_8025(u8 addr)
{
    u8 date;
    Start();
    SendData(0x64);
    RecvACK();
    SendData(addr);
    RecvACK();
    Start();
    SendData(0x65);
    RecvACK();
    date = RecvData();
    SendNAK();
    Stop();
    return date;
}
//----BCD转10进制换算函数用于时钟输出--------
u8 BCD_D(u8 num)
{
    u8 L;
    L=(num/16)*10+(num%16);
    return L;
}
//----10进制转BCD换算函数用于时钟设置--------
u8 D_BCD(u8 num)
{
    u8 L;
    L=(num/10)*16+(num%10);
    return L;
}
//====打包读出RX8025实时时间数据========================================
//读取寄存器的数据为二--十进制编码(BCD)格式
//数据变换成十进制数据(数据编码为十六进制后台运行为二进制)
void read_8025time(u8 *timedata)
{
    u8 i;
    for(i=0; i<7; i++) //分 7 次读取 秒分时日月周年
   {

timedata=BCD_D(read_8025(i);
}
}
//====打包写入RX8025初始化的调整后的时间数据==========================
//写入寄存器的数据为BCD格式数据
void write_8025time(u8 *timedata)
{
    u8 i;
    for (i=0; i<7; i++)  //7 次写入 秒分时日月周年
   {
        write_8025(i,D_BCD(timedata));

    }
}
//====分别读取时间数据============================
void read_8025data()
{
    read_8025time(&time);
    ye=time[6];
    mo=time[5];
    da=time[4];
    hi=time[2];
    mi=time[1];
    si=time[0];
}
//====RX_8025初始化函数==================================
void init_8025()
{
    u8 VLF;
//~~~~以下为是否初始化时间的判断操作~~~~
    VLF=((read_8025(0x0E))&0x02);//读标志寄存器E的VLF位,如果为1则提示实时时间数据丢失
    if(VLF)
    {
        write_8025(0x0E,0x00);  //清除所有标志
        write_8025time(&time_init);//如因掉电而数据丢失则重新上电时显示20-1-1 8:30:00星期3
    }
//~~~~以下为时间(秒)更新中断的设置~~~~
    write_8025(0x0F,0x00);  //设置UIE=0关闭更新中断
    write_8025(0x0D,0x00);  //设置USEL=0(设为秒更新)
    write_8025(0x0F,0xE0);  //设置UIE=1使能更新中断启动INT、关闭其他中断,设置间隔30S温补一次(CSEL0,1=10)
}
五、关于开天斧板子的使用有几个问题需要注意一下:
1.上手时先处理与外部设备的电源电压的匹配问题,板子默认为5V供电、5V输出,如果外部设备是3.3V时需要修改板上的相关电阻的位置,使板上标注VCC的引脚电压为3.3V。
2.用到板子的接口连接外部设备时,也需要根据原理图核对相关引脚是否连接了其他功能的电路,需要加焊、挪移、去除一些与引脚连接的电阻才可以正常使用。
3.上述这些在原理图上都有详细标注,用之前需要相信查看原理图。
六、关于STC8H头文件的一点使用心得的经验分享:
STC8H.h头文件是个挺奇葩的头文件,使用STC8单片机时建议仔细查看这个头文件,因为它包罗万象,比如引用了这个头文件就不用在程序中做下列宏定义了:
#define uchar unsigned char
#define uint unsigned int
#define u32 unsigned long
直接就用u8,u16,u32就可以了因为头文件里有宏定义了,如果是自己使用的话还可以自行丰富这个头文件,例如,STC8H单片机使用时必须首先设置I/O口,否则他是无法运行的,我就曾经弄了很久也没能点亮LED灯,于是我在头文件里就添加了如下代码:
#define GPIO_set() {P0M0 = 0x00; P0M1 = 0x00; P1M0 = 0x00; P1M1 = 0x00;P2M0 = 0x00; P2M1 = 0x00;P3M0 = 0x00; P3M1 = 0x00;P4M0 = 0x00; P4M1 = 0x00;P5M0 = 0x00; P5M1 = 0x00;P6M0 = 0x00; P6M1 = 0x00;P7M0 = 0x00; P7M1 = 0x00;}
此后建立工程后只要在主函数的主循环前加入一条:GPIO_set() ; 就可以少写一大堆的PxMx=0x00端口设置代码了,另外,这个单片机经常要用到sfrx寄存器P_SW2的开关设置,只要在主函数开头加上 EAXSFR();这句代码就可以在各个函数中无视P_SW2寄存器的设置了,比如使用内部RTC是,你可以直接使用   YEAR;MONTH;DAY;HOUR;MIN;SEC;这些变量字来调用RTC寄存器中的数据而不用另外定义变量了,因为头文件中已经定义好了(不同的头文件可能拼写有不同)。如上这些还有很多仔细查看这个头文件可以大大的方便编程。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

发表于 2023-3-1 18:49:29 来自手机浏览器 | 显示全部楼层
慕名而来 发表于 2023-3-1 11:52
开天斧板子使用RX8025T是没问题的,只要启用它的硬件I2C总线挂载8025就可以了,另外,还有一个简易方案, ...

老哥费心了…我现在的业余时间不怎么多了,钱不好赚…玩单片机的话耗时也太长,这段时间折腾一下电源,比单片机少费点时间……单片机也就是放假的时候能玩,很多时候粘贴复制代码一旦被其他的事情打断再回来就很不爽…
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-3-1 20:04:56 | 显示全部楼层
触景情伤 发表于 2023-3-1 18:49
老哥费心了…我现在的业余时间不怎么多了,钱不好赚…玩单片机的话耗时也太长,这段时间折腾一下电源,比 ...

说的是,底层谋生越来越难了。
回复 支持 反对

使用道具 举报

发表于 2023-3-5 19:42:29 | 显示全部楼层
标记,学习一下。
回复 支持 反对

使用道具 举报

发表于 2023-4-3 13:23:11 | 显示全部楼层
慕名而来 发表于 2023-3-1 20:04
说的是,底层谋生越来越难了。

可以用 STC-ISP V6.91M 的调试接口,虚拟 480*320显示,省点成本




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

头像被屏蔽
发表于 2023-4-4 09:41:20 | 显示全部楼层
慕名而来 发表于 2023-3-1 20:04
说的是,底层谋生越来越难了。

是啊,这几年大家都不容易,STC也考虑到这点,全部免费+包邮送你们核心开发板,减轻工程师开发的压力和成本。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-4-4 10:15:29 | 显示全部楼层
疯狂的兔子来了 发表于 2023-4-4 09:41
是啊,这几年大家都不容易,STC也考虑到这点,全部免费+包邮送你们核心开发板,减轻工程师开发的压力和成 ...

确实要感谢你们这些国产品牌的良心厂家,其他的都不说至少可以使很多有学习单片机开发技术的人得以无门槛接触实物并快速上手,就此而言厂家及那些热心员工也是功德无量的。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-8 05:40 , Processed in 0.202800 second(s), 12 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表