摘要: 虽然8051兼容的微控制器与SPI端口是可用的,一个低成本的设备与SPI端口位通过GPIO引脚通常就足够了。本应用程序说明中显示的代码利用了8051特有的特性来创建一个位固定的SPI端口。
快速SPI端口可以通过GPIO引脚进行位冲击,并作为具有SPI端口的8051兼容微控制器的低成本替代方案。本应用笔记中显示的代码利用8051特定的功能,使用最少的额外代码创建快速SPI端口。
虽然8051兼容的微控制器与SPI端口是可用的,一个低成本的设备与SPI端口位通过GPIO引脚通常足以满足许多应用。这里显示的代码利用了特定于8051核心的特性,以最小的努力创建快速SPI端口。的CPHA
,CPOL
,CS_TOGGLE_BETWEEN_BYTES
中的常数#定义
语句初始化宏,使代码适合要实现的SPI端口类型。预处理器在编译时而不是在运行时执行这种代码裁剪,从而节省了宝贵的时钟周期,如果决策结构(例如,常规的if - else
语句)被使用。
下面的代码包括利用8051内核特性所需的特定于8051的C命令。虽然这些命令是特定于编译器的(在这种情况下是用于8051的KeilµVision v2 Development Tools),但所有用于8051兼容设备的“好的”C编译器都包含类似的命令。
检查代码,PORT_0
定义为类型sfr
,它提醒编译器该标签是一个8051特殊功能寄存器(SFR)。因为这个SFR是位可寻址的,所以sbit
type定义了引用特定SFR位作为SPI端口引脚的标识符。的bdata
中使用的类型spiTmp
声明允许将此变量放置在8051核心的直接可寻址RAM中的特殊位可寻址内存中。再一次,sbit
类型中定义了引用特定位的标识符spiTmp
变量。
通过SPI端口发送的字节被加载到全局字节数组中,spiData
. 将此变量声明为全局允许SPI发送/接收函数访问spiData
而不需要将其作为参数传递。用数据
标识符强制编译器将数组存储在8051内核内最快的可访问内存(直接可寻址内存)中。
的spiReadWriteBlock
函数包含位绑定SPI端口的代码。它有效地传输数据中的每个字节spiData
使用此SPI端口的数组,从数组中的最后一个元素到第一个元素。使用这种反向顺序访问数组允许与零进行比较(见代码),由于8051指令集,这将转化为更快的汇编。当spiReadWriteBlock
功能完成后,用SPI端口读取的字节将取代原有的数据spiData
数组,还是从数组的最后一个元素开始到第一个元素。
注意,代码经过优化,可以发送和接收大于一个字节的数据块。对于单字节传输,循环结构和内部的局部变量spiReadWriteBlock
应该被移除。(这可以使用预处理器来完成。)
当为运行在32MHz的器件DS89C430/450系列8051兼容微控制器编译时,这个位撞击SPI端口的运行速度刚刚超过2Mbps,如图1所示。此外,代码只需要两个字节的可直接寻址RAM和139字节的闪存作为代码空间(包括SPI端口初始化和主程序循环)。
图1所示、当CPHA、CPOL和CS_TOGGLE_BETWEEN_BYTES常量设置为1时,这些波形表示来自位碰撞SPI端口的输出。该固件使用8051内核中的位可寻址内存来提高SPI端口的速度
/* ********************************************************** * 8051年Bit-Banged SPI * *格言集成产品 * ********************************************************** */// 常量 ----------------------------------------------# 定义CPOL 1 / / CPOL设置为1或0 # define CPHA 1 / / CPHA设置为1或0 # define CS_TOGGLE_BETWEEN_BYTES 1 / / CS切换/ / 0 = false 1 = true # define N_OF_SPI_BYTES 3 / /宏 ------------------------------------------------- # 如果如果CPOL CPHA #定义SCK_POST ##define SCK_INIT 1 #define SCK_PRE SCK=0 #define SCK_MID SCK=1 #else #define SCK_INIT 0# define SCK_PRE SCK=1 #define SCK_MID SCK=0 #endif#else #define SCK_INIT 1 #define SCK_MID SCK=0 #define SCK_POST SCK=1 #define SCK_MID SCK=1 #define SCK_POST SCK=0 #endif#if CS_TOGGLE_BETWEEN_BYTES #define CS_TOGGLE CS=1;CS=0#else #define CS_TOGGLE#endif// PIN定义----------------------------------------sfr PORT_0 = 0x80;sbit CS= PORT_0 ^1; sbit SCK = PORT_0 ^ 2; sbit莫西人= PORT_0 ^ 3; sbit味噌= PORT_0 ^ 4; / /全局变量 --------------------------------------- 无符号字符数据spiData [N_OF_SPI_BYTES]; / / BIT-ADDRESSABLE全局变量 ----------------------- 无符号字符bdata spiTmp; sbit spiTmp7 = spiTmp ^ 7; sbit spiTmp6 = spiTmp ^ 6; sbit spiTmp5 = spiTmp ^ 5; sbit spiTmp4 = spiTmp ^ 4, sbit spiTmp3 = spiTmp ^ 3; sbit spiTmp2 = spiTmp ^ 2; sbit spiTmp1 = spiTmp ^ 1; sbit spiTmp0 = spiTmp ^ 0; / /函数原型------------------------------------ 空白spiReadWriteBlock(空白);/ / spiReadWriteByte函数 ------------------------------// // 数据转移从spiData [N_OF_SPI_BYTES-1] / / spiData [0] MSb第一。接收到的数据将替换spiData[N_OF_SPI_BYTES-1]到spiData[0]的//现有数据。////注意:此函数假设// SCK=SCK_INIT和CS=1void spiReadWriteBlock(void){unsigned char data i = N_OF_SPI_BYTES-1;Cs = 0;while(1) {spiTmp = spiData[i];SCK_PRE;莫西人= spiTmp7;SCK_MID;spiTmp7 =味噌;SCK_POST;//位7 SCK_PRE;莫西人= spiTmp6;SCK_MID;spiTmp6 =味噌;SCK_POST;// bit 6 SCK_PRE;莫西人= spiTmp5;SCK_MID;spiTmp5 =味噌;SCK_POST;//位5 SCK_PRE;莫西人= spiTmp4;SCK_MID;spiTmp4 =味噌;SCK_POST;// bit 4 SCK_PRE;莫西人= spiTmp3;SCK_MID;spiTmp3 =味噌;SCK_POST;// bit 3 SCK_PRE;莫西人= spiTmp2;SCK_MID;spiTmp2 =味噌;SCK_POST;// bit 2 SCK_PRE;莫西人= spiTmp1;SCK_MID;spiTmp1 =味噌;SCK_POST;// bit 1 SCK_PRE;莫西人= spiTmp0;SCK_MID;spiTmp0 =味噌;SCK_POST;// bit 0 spiData[i] = spiTmp;If (i == 0) break;我,;CS_TOGGLE;} CS = 1;} / /主要 --------------------------------------------------- void main (void){/ / 0。Init SPI Pins CS = 1;SCK = sck_init;/ / 1。程序循环……while (1) {spiData[2] = 0x40;spiData[1] = 0x41;spiData[0] = 0x42;spiReadWriteBlock ;}}
这篇文章的类似版本出现在2005年5月2日的EE Times杂志上。
社群二维码
关注“华强商城“微信公众号
Copyright 2010-2023 hqbuy.com,Inc.All right reserved. 服务热线:400-830-6691 粤ICP备05106676号 经营许可证:粤B2-20210308