数码之家

 找回密码
 立即注册
搜索
查看: 1510|回复: 5

关于stm32位带的那些事,以及C51的12864代码移植

[复制链接]
发表于 2019-6-13 14:14:54 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

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

x
昨天第一次用stm32点亮了LED,然后点亮了12864。
这个时候,我想想STC单片机那样利用ACC直接快速传输数据。(C51的12864IIC驱动代码我已经上传到附件里面了,希望能帮到你们使用12864液晶屏)
像这样(12864的IIC驱动方式写指令和写数据):
sbit ACS1 = ACC^0;
sbit ACS2 = ACC^1;
sbit ACS3 = ACC^2;
sbit ACS4 = ACC^3;
sbit ACS5 = ACC^4;
sbit ACS6 = ACC^5;
sbit ACS7 = ACC^6;
sbit ACS8 = ACC^7;

void IIC12864_Write_Data(unsigned char DATA)  //发送一条数据
{
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
       
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;          //发送0x78
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
       
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
       
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;          //发送0x40
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
       
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        ACC=DATA;                                                                                   //发送数据
        IIC12864_SDA=ACS8;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS7;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS6;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS5;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS4;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS3;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS2;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS1;IIC12864_SCL=1;IIC12864_SCL=0;           //数据发送完成
       
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SCL=1;IIC12864_SDA=0;IIC12864_SDA=1;
}

void IIC12864_Write_Command(unsigned char DATA)  //发送一条指令
{
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
       
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;          //发送0x78
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
       
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
       
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;          //发送0x00
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=0;IIC12864_SCL=1;IIC12864_SCL=0;
       
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        ACC=DATA;                                                                                   //发送指令
        IIC12864_SDA=ACS8;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS7;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS6;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS5;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS4;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS3;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS2;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SDA=ACS1;IIC12864_SCL=1;IIC12864_SCL=0;           //指令发送完成
       
        IIC12864_SDA=1;IIC12864_SCL=1;IIC12864_SCL=0;
        IIC12864_SCL=1;IIC12864_SDA=0;IIC12864_SDA=1;
}


这些代码在51单片机上面完全可以用;但是想要移植到STM32平台上时就通过移位操作写数据了。
后来,我发现STM32的位带可以包括SRAM区,就用这个特性写出了类似的代码
unsigned char  ACS __attribute__((at(0x2000A000)))=0;         //此地址仅能用于SRAM区域大于40K的类型
#define ACS1   *((volatile unsigned long  *)(0x22140000))
#define ACS2   *((volatile unsigned long  *)(0x22140004))
#define ACS3   *((volatile unsigned long  *)(0x22140008))
#define ACS4   *((volatile unsigned long  *)(0x2214000C))
#define ACS5   *((volatile unsigned long  *)(0x22140010))
#define ACS6   *((volatile unsigned long  *)(0x22140014))
#define ACS7   *((volatile unsigned long  *)(0x22140018))
#define ACS8   *((volatile unsigned long  *)(0x2214001C))

后面的事说是意外也不意外,因为STM32的I/O翻转速度过快(我设定的是最大50MHZ,程序限制可能是至少10MHZ)导致显示屏花屏(加了延时就正常显示)。
看来速度过快也不一定是好事......
问题就是来源于以上冗长的故事:
在完成以上代码的时候,我发现STM32的位带区是从0x20000000到0x21000000,一共1MB。
但是我所使用的芯片却只有48K的SRAM。
再查过了STM32F1的选型表后,我发现F1系列的SRAM最大只有64KB。
那么,这是不是意味着STM32F1可以全区域位带操作?有人知道吗?
是不是随意定义一个变量,通过指针取地址以后,经过位带算法,都可以直接实现位操作?
如果可以这么做的话,那么操作显示缓冲区就可以变得极其方便,也可以衍生出STM32平台下的其他特有代码。


补充内容 (2019-6-14 22:11):
现在已经证明,STM32极其有可能是全部片内SRAM区域都能位带操作的!
有兴趣的话,可以试试(相关计算代码我将发到回复里面)。
这是C51版本的使用方式.png

12864-串行IIC.zip

2.58 KB, 下载次数: 1, 下载积分: 家元 -55

这个是C51版本的IIC驱动,请注意要自己定义两个IO变量才能运行

发表于 2019-6-13 22:36:36 | 显示全部楼层
STM32硬件IIC,有HAL库支持,使用还是蛮方便的
回复 支持 反对

使用道具 举报

发表于 2019-6-14 15:52:01 | 显示全部楼层
自己好好看看手册,只有部分寄存器是支持位带的。
位带的地址跟ram的地址不是一回事,这个是映射出来的,,其实是mcu的寻址空间。
16位机的寻址能力就是2的16次方,8位机是2的8次方,32位机就是2的32次方。类推。
ram也只是映射到寻址空间的其中一部分。也就是说,无论是位带区,还是64kram区,都是2的32次方中的一部分。
回复 支持 反对

使用道具 举报

发表于 2019-6-14 17:17:44 | 显示全部楼层
楼主的思路很独特,我从来没这么用过.

大概看了一下手册,好像可以这么用,也就是说可以对内置RAM的位带别名直接进行位操作.如果楼主验证成功,告诉大家一声啊,以后再遇到大量位操作的运算时,就可以用位带来做,能加快不少呢.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-14 22:38:06 | 显示全部楼层
简燕 发表于 2019-6-14 17:17
楼主的思路很独特,我从来没这么用过.

大概看了一下手册,好像可以这么用,也就是说可以对内置RAM的位带别名 ...

我试了一下,貌似STM32中我见到的所有变量都能这样做:(以下代码已经编译通过了,下载后输出也没问题)
u32  SRAMA,SRAMB;
u32  *SRAMA0,*SRAMA1,*SRAMB0,*SRAMB1;
u32*  get_bit_of_adrs (u32 *adrs_ram,u8 n)
{
        u32 adrsout=0;
        adrsout=0x22000000+((u32)(adrs_ram -0x20000000)<<5)+(n*4);
        return (u32*)adrsout;
}
SRAMA0=get_bit_of_adrs(&SRAMA,0);
SRAMA1=get_bit_of_adrs(&SRAMA,1);
SRAMB0=get_bit_of_adrs(&SRAMB,0);
SRAMB3=get_bit_of_adrs(&SRAMB,3);
*SRAMA0=*SRAMA1;
*SRAMA1=*SRAMB3;
看起来STM32极有可能是全部SRAM区域都可以这么做的
通过这个函数直接就可以获得特定位的地址,在定义一个数组或者特殊数据处理缓冲区的时候,应该可以发挥很大的作用。
回复 支持 反对

使用道具 举报

发表于 2019-6-15 17:50:06 | 显示全部楼层
STM32是基于Cortex-M3的,该CPU使用了统一编址架构,所有的外设,片内片外都有一个确定的地址供CPU使用格式化的Load/Store操作访问。由于内核是32bit的,所以拥有4GB寻址能力。其中的某些连续地址区就被按位在另一块连续的地址区上映射,映射出来的区就是位带区。如果片内的SRAM地址恰好全部处于被映射的地址区里,那确实全部SRAM单元都可以位带操作。具体手册有说明。
回复 支持 反对

使用道具 举报

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

本版积分规则

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

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2024-4-17 04:27 , Processed in 0.327600 second(s), 13 queries , Redis On.

Powered by Discuz!

© 2006-2023 smzj.net

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