这个感光模块主要就是用i2c通信,移植的时候其实就是改一下延时,把端口的模式设置正确就行了
为了尽量减少工作量,我尽量多用宏定义定义,少修改代码,对于延时函数,可以用define 把它替换成stm32里的延时函数 对于变量,注意在stm32里int是四个字节,而51是两个字节,再者就是很关键的一点,51里有bit变量,可以位寻址 而stm32却没有,而且也没有sbit,对于前者,我就直接把它变成uchar,而后者是有解决办法的,就是位带操作。
位带操作就是,设定了一块特殊的地方,映射到其他地址,每个位对应一个四个字节长度的地方,而访问这个映射的地址,就间接的能访问到位了,因此想要将某一位置一或零可以直接对这个地址进行操作,定义这个地址和51不一样,51是i/o映射,即i/o口和RAM地址是各自独立的,而stm32作为arm,是内存映射,即io口和内存地址统一编码。51是用sfr定义,stm32则可以这样#define RAM_ADDR (*(volatile unsigned LONG *)0x0000555F)
以下解释来自点击打开链接
先把它强制转换为指针类型 (unsigned CHAR *)0x5F,AVR的SREG是八位寄存器,所以0x5F强制转换为指向 unsigned CHAR类型。 volatile(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种“意想不到地改变”,不是由程序去改变,而是由硬件去改变——意想不到。 第二步,对指针变量解引用,就能操作指针所指向的地址的内容了 *(volatile unsigned CHAR *)0x5F 第三步,小心地把#define宏中的参数用括号括起来,这是一个很好的习惯,所以#define SREG (*(volatile unsigned CHAR *)0x5F)
关于volatile
因为 C 编译器并不知道同一个比特可以有两个地址。所以就要通过 volatile,使得编译器每次都如实地把新数值写入存储器,而不再会出于优化的 虑 在中途使用寄存器来操作数据的复本,直到最才把复本写回(这和 cache 的原理是一样的)
类似的,如果使用一个32位处理器,要对一个32位的内存地址进行访问,可以这样定义#define RAM_ADDR (*(volatile unsigned LONG *)0x0000555F) 然后就可以用C语言对这个内存地址进行读写操作了 读:tmp = RAM_ADDR; 写:RAM_ADDR = 0x55;
这样基本就可以像51一样操作端口
再就是端口模式 输出时推挽模式 输入浮空模式
以上注意好的话就大功告成了 本来应该是这样的,不过由于本人的粗心大意,还犯了个错误,一般的时间都花在这上面了
因为是移植,我并没有仔细看别人写的代码内容,对于位CY直接当作普通的位寻址的变量来替换了,实际上CY是保存计算后内容的位,和上一次计算有关,我没注意到,所以一直读出的是111111.。。。所以移植的时候还是要大致看看比人的代码,要搞清变量的作用
代码点击打开链接
这里是后话,最近又把一个湿度传感器51代码移植到stm32上,又出现了一些问题,这里总结一下
移植时的注意:
1,端口:通过位带操作将原先端口通过宏定义来替换成相应的stm32端口,特别注意给端口赋值和读取是要两个不同的端口宏定义的,一定仔细看代码修改,输出推挽模式,输入浮空(或上拉输入经测试也可以),读取数据之前要换输入模式
2,关于时间的:延时函数,us和ms通过宏定义或者写新的函数,且用于计算时间长短的变量也要改视情况改长度(如等待应答信号的计数值)
3,改变量:最好把所有的变量类型都检查下改成合适的
4,调试时printf是很方便,但是要注意printf消耗的时间是不小的!!!至少已经能影响时序的正确性了,调时序一定要慎用!!!
关于湿度传感器dht11多说一句,那个引脚比常用的要细,一定要插牢 否则接触不好容易出问题 (初始化失败)