第四章 c51 程序设计 -2 实例

48
第第第 C51 第第第第 -2 第第 开开开开开 6 9 10 12 开开开开开开开开 开开开开 5 00 开开开开开开开开开

Upload: tobit

Post on 24-Jan-2016

190 views

Category:

Documents


10 download

DESCRIPTION

第四章 C51 程序设计 -2 实例. 开题报告第 6 , 9 , 10 , 12 还没有发给齐老师,明天下午 5 : 00 之前必须交给齐老师。. 1-wire 总线及应用. 一根数据线。设备(主机或从机)通过一个漏极开路端口,连接至该数据线,这样允许设备在不发送数据时释放数据总线,以便总线被其它设备所使用。 1-wire 总线端口为漏极开路,单总线要求外接一个约 5k 的上拉电阻,这样单总线的闲置状态为高电平。 主机对 1-Wire 总线的基本操作分为复位、读和写三种,其中所有的读写操作均为低位在前,高位在后。 典型的单总线命令序列 第一步 初始化; - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第四章   C51 程序设计 -2 实例

第四章 C51 程序设计 -2 实例

开题报告第 6 , 9 , 10 , 12 还没有发给齐老师,明天下午 5 : 00 之前必须交给齐老师。

Page 2: 第四章   C51 程序设计 -2 实例

1-wire 总线及应用 一根数据线。设备(主机或从机)通过一个漏极开路端口,

连接至该数据线,这样允许设备在不发送数据时释放数据总线,以便总线被其它设备所使用。 1-wire 总线端口为漏极开路,单总线要求外接一个约 5k 的上拉电阻,这样单总线的闲置状态为高电平。

主机对 1-Wire 总线的基本操作分为复位、读和写三种,其中所有的读写操作均为低位在前,高位在后。

典型的单总线命令序列 第一步 初始化; 第二步 ROM 命令 跟随需要交换的数据; 第三步 功能命令 跟随需要交换的数据;

Page 3: 第四章   C51 程序设计 -2 实例

实例: DS18B20 单线温度传感器 主要特征

全数字温度转换及输出。 1-wire 总线数据通信。 最高 12 位分辨率,精度可达土 0.5 摄氏度。 12 位分辨率,最大工作周期为 750 毫秒。 检测温度范围为 -55 ~+125℃ ℃ 。 内置 EEPROM ,限温报警功能。 64 位光刻 ROM ,内置产品序列号,方便多机挂接。 多样封装形式,适应不同硬件系统。

Page 4: 第四章   C51 程序设计 -2 实例

DS18B20 工作原理 三种形态的存储器资源

ROM 只读存储器,用于存放 DS18B20ID 编码。 RAM 数据暂存器,用于内部计算和数据存取,数据在掉电后丢失, DS18B20 共 9 个字节 RA

M ,每个字节为 8 位。 EEPROM 非易失性记忆体,用于存放长期需要保存的数据,上下限温度报警值和校验数据。

RAM 及 EEPROM结构图:

Page 5: 第四章   C51 程序设计 -2 实例

控制器对 18b20 操作流程 复位:给 DS18B20 单总线至少 480uS 的低电平信号。 存在脉冲:复位电平结束之后,控制器应该将数据单总线拉高,以便于

在 15~60uS 后接收存在脉冲,存在脉冲为一个 60~240uS 的低电平信号。

控制器发送 ROM 指令: ROM 指令共有 5 条,每一个工作周期只能发一条, ROM 指令分别是读 ROM 数据、指定匹配芯片、跳跃 ROM 、芯片搜索、报警芯片搜索。(一般只挂接单个 18B20 芯片时可以跳过ROM 指令)

控制器发送存储器操作指令:分别是写 RAM 数据、读 RAM 数据、将RAM 数据复制到 EEPROM 、温度转换、将 EEPROM 中的报警值复制到 RAM 、工作方式切换。

执行或数据读写:一个存储器操作指令结束后则将进行指令执行或数据的读写,这个操作要视存储器操作指令而定。

Page 6: 第四章   C51 程序设计 -2 实例

几种时间隙 DS18B20 复位及应答关系

写时间隙

Page 7: 第四章   C51 程序设计 -2 实例

读时间隙

注意:必须在读间隙开始的 15uS 内读取数据位才可以保证通信的正确。 DS18B20 与单片机接法

Page 8: 第四章   C51 程序设计 -2 实例

示例程序:void Init_DS18B20(void) //18b20 初始化 {

DQ = 1; //DQ 复位_nop_();_nop_();_nop_(); DQ = 0; // 拉低 DQ delay(200); // 约 600usDQ = 1; // 拉高总线 delay(20); // 75us,30:100us

}

Page 9: 第四章   C51 程序设计 -2 实例

uchar Read_byte(void) // 读一字节 {

uchar i=0; uchar dat = 0; for (i=8;i>0;i--) {

DQ = 1;_nop_();_nop_();_nop_();_nop_();DQ = 0; // 从高拉到低,产生读时间隙_nop_();_nop_(); // 至少保持低电平 1us_nop_();_nop_();_nop_();_nop_();dat>>=1; // 右移一位DQ = 1; //15us 内停止将 DQ 拉低 ,15us 内数据有效_nop_();_nop_(); // 稍作延时_nop_();_nop_();if(DQ) // 若高电平 置 1dat|=0x80; delay(30); // 至少保持 60us , 100us, 确保读数据成功

} DQ = 1; // 结束拉高 return(dat);

}

Page 10: 第四章   C51 程序设计 -2 实例

void Write_byte(uchar dat) // 写一个字节 {

uchar i=0; for (i=8; i>0; i--) {

DQ = 1;_nop_();_nop_(); // 稍作延时 _nop_();_nop_();_nop_();_nop_();DQ = 0; // 拉低 DQ 开始写 _nop_();_nop_();_nop_();_nop_(); //15us 内释放总线 _nop_();_nop_();_nop_();_nop_();DQ = dat&0x01; // 从 lsb 开始 delay(20); //75us 至少需保持 60us 写时间隙dat>>=1; // 右移一位

}DQ = 1; // 结束拉高delay(4);

}

Page 11: 第四章   C51 程序设计 -2 实例

uint Get_Temperature(void) // 读温度函数{

uchar a=0; uchar b=0;

uint t=0; Init_DS18B20(); Write_byte(0xCC); // 只接一个 18b20 芯片, skip ROM Write_byte(0x44); // 温度转换

delay(200); // 延时 600us 等待转换完成 , 一般转换时间为 500us Init_DS18B20(); Write_byte(0xCC); //skip ROM Write_byte(0xBE); // 从 RAM 读数据 a=Read_byte(); // 先读低位 b=Read_byte(); // 再读高位 t=b<<8; t=t|a; //t 为最后读得的数据

return (t); }

Page 12: 第四章   C51 程序设计 -2 实例

双向二线制串行通信总线,时钟线 SCL, 数据线 SDA 。 NXP 半导体(原 Philips 半导体)于 20 多年前发明。 I2C 总线是同步串行数据传输总线。 经常使用的带 I2C 总线通用外围器件有: SRAM 、 E2P

ROM 、 ADC/DAC 、 RTC 、 I/O 口等。 带 I2C 总线的外围设备模块有由 LED 驱动控制器构成的

LED 显示器,由各种 LCD 驱动控制器构成的段式、字符点阵、图形点阵液晶显示器等。

I2C 总线及应用

Page 13: 第四章   C51 程序设计 -2 实例

I2C 总线的信号线 I2C 总线只需要由两根信号线组成,一根是串行数据线 SD

A ,另一根是串行时钟线 SCL ,均为为开漏结构,故总线上必须有上拉电阻 Rp ,通常可选 5 ~ 10kΩ 。

Page 14: 第四章   C51 程序设计 -2 实例

I2C 总线时序定义: 起始条件和停止条件( START and STOP conditions )

起始条件:当 SCL 处于高电平期间时, SDA 从高电平向低电平跳变时产生起始条件。总线在起始条件产生后便处于忙的状态。起始条件常常简记为 S 。

停止条件:当 SCL 处于高电平期间时, SDA 从低电平向高电平跳变时产生停止条件。总线在停止条件产生后处于空闲状态。停止条件简记为 P 。

Page 15: 第四章   C51 程序设计 -2 实例

I2C 总线上数据的有效性( Data validity ) 数据线 SDA 的电平状态必须在时钟线 SCL 处于高电平

期间保持稳定不变。 SDA 的电平状态只有在 SCL 处于低电平期间才允许改变。但是在 I2C 总线的起始和结束时例外。

Page 16: 第四章   C51 程序设计 -2 实例

从机地址( Slave Address ) I2C 总线不需要地址译码器和片选信号。多个具有 I2C 总线接口的器件

都可以连接到同一条 I2C 总线上,它们之间通过器件地址来区分。 主机是主控器件,它不需要器件地址,其它器件都属于从机,要有器件地

址。必须保证同一条 I2C 总线上所有从机的地址都是唯一。 一般从机地址由 7 位地址位和一位读写标志 R/W 组成, 7 位地址占据

高 7 位,读写位在最后。读写位是 0 ,表示主机将要向从机写入数据;读写位是 1 ,则表示主机将要从从机读取数据。

从机地址由一个固定和一个可编程的部分构成。从机地址的可编程部分使最大数量的相同器件可以连接到 I2C 总线上,器件可编程地址位的数量由管脚决定,如果器件 3 个可编程的地址管脚,那么 I2C 总线上共可以连接 8 个相同的器件。

Page 17: 第四章   C51 程序设计 -2 实例

I2C 数据传输的方式 以字节( Byte )为单位收发数据。首先传输的是数据的最高位

( MSB ,第 7 位),最后传输的是最低位( LSB ,第 0 位)。另外,每个字节之后还要跟一个响应位,称为应答。

应答( Acknowledge ) 每传输一个字节,要跟一个应答状态位。接收器接收数据的情况

可通过应答位来告知发送器。应答位的时钟脉冲由主机产生,而应答位的数据状态则遵循“谁接收谁产生”的原则,即总是由接收器产生应答位。主机向从机发送数据时,应答位由从机产生;主机从从机接收数据时,应答位由主机产生。

I2C 总线上第 9 个脉冲对应应答位, SDA 为 0 表示接收器应答( ACK ), A ;为 1 则表示非应答( NACK ), /A 。

Page 18: 第四章   C51 程序设计 -2 实例

基本的数据传输格式

主机向从机发送数据的基本格式

主机从从机接收数据的基本格式

注意:主机向从机发送最后一个字节的数据时,从机可能应答也可能非应答,但不管怎样主机都可以产生停止条件。如果主机在向从机发送数据(甚至包括从机地址在内)时检测到从机非应答,则应当及时停止传输。

Page 19: 第四章   C51 程序设计 -2 实例

数据传输时序图

主机向从机写数据 ( 24LC01 )

Page 20: 第四章   C51 程序设计 -2 实例

主机读从机数据( 24LC01 )

Page 21: 第四章   C51 程序设计 -2 实例

EEPROM —— 24LC01B

主要特征 低至 2.5V 的单电源供电; 低功耗的 CMOS 技术; 128 bytes ( 128×8 )的存储块; 标准 2 线串行接口总线 , I2C 总线; 兼容 100 kHz (2.5V) 、 400kHz (5.0V) ; 高达 8 bytes 的页写入缓存; 2 ms 页写入时间周期; 硬件写保护。

Page 22: 第四章   C51 程序设计 -2 实例

硬件电路

Page 23: 第四章   C51 程序设计 -2 实例

I2C 通过 IO 口模拟void Start(void) // 起始信号{

Sda=1;Scl=1;delay1us();Sda=0;delay1us();

}

void Stop(void) // 停止{

Sda=0;Scl=1;delay1us();Sda=1;delay1us();

}

Page 24: 第四章   C51 程序设计 -2 实例

void Ack(void) // 应答{

Sda=0;delay1us();Scl=1;delay1us();Scl=0;

}

void NoAck(void) // 不应答{

Sda=1;delay1us();Scl=1;delay1us();Scl=0;

}

Page 25: 第四章   C51 程序设计 -2 实例

void Send(unsigned char Data) // 发送字节{

unsigned char xdata BitCounter=8; unsigned char xdata temp;

do{temp=Data;Scl=0;delay1us();

if((temp&0x80)==0x80)Sda=1;

elseSda=0;

delay1us();Scl=1;delay1us();temp=Data<<1; //左移 1 位Data=temp;BitCounter- -;}while(BitCounter);Scl=0;

}

Page 26: 第四章   C51 程序设计 -2 实例

unsigned char Read(void) // 读取字节{

unsigned char xdata temp=0;unsigned char xdata temp1=0;unsigned char xdata BitCounter=8;Sda=1;do{

Scl=0;delay1us();Scl=1;delay1us();if(Sda)

temp=temp|0x01; else

temp=temp&0xfe; if(BitCounter-1){ temp1=temp<<1; temp=temp1;}BitCounter- -;

}while(BitCounter);return(temp);

}

Page 27: 第四章   C51 程序设计 -2 实例

void WrToROM(unsigned int Data_Write,unsigned char Address)//Data_Write: 要写的整数, Address: 写入的起始地址

{unsigned char xdata Temp_Data;Start(); Send(0xa0); Ack();Send(Address); Ack();Temp_Data=(Data_Write>>8) & 0xff; // 先写高 8 位Send(Temp_Data);Ack();Stop();delay1ms(5);Start(); Send(0xa0); Ack();Send(Address+1); Ack();Temp_Data=Data_Write & 0xff; // 低 8 位Send(Temp_Data);Ack();Stop();delay1ms(5);

}

Page 28: 第四章   C51 程序设计 -2 实例

unsigned int RdFromROM(unsigned char Address) // 读取数据{

unsigned int xdata Temp_Data;Start();Send(0xa0);Ack();Send(Address);Ack();Start();Send(0xa1);Ack();Temp_Data=(Read())*256; // 高 8 位NoAck();Stop();delay1ms(5);Start();Send(0xa0);Ack();Send(Address+1);Ack();Start();Send(0xa1);Ack();Temp_Data += Read(); // 低 8 位NoAck();Stop();delay1ms(5);return Temp_Data;

}

Page 29: 第四章   C51 程序设计 -2 实例

通过单片机自带 I2C 接口P89C669 自带 I2C 功能实现对 EEPROM 单字节的读取与写入,写入单个字节和读取只要分别调用 bit ISendbyte_1(uchar sla,uchar suba,uchar c) 和 bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no)即可,参考资料: P89C669 I2C软件包。

/*******************************************************************申请总线功能:进行 I2C 总线的初始化包括时钟速率 I2C 使能发送起始信号等 *******************************************************************/void GetBus(){

I2CON=0xc4; //use internal SCL generatorI2CLL=50; //bits data rate=fosc/(I2CLL+I2CLH)I2CLH=50;I2CON=I2CON|0x20; /*STA=1,申请成为主机起动总线 */ while(SI==0);

}/*******************************************************************发送数据函数 功能:用于向总线发送数据 *******************************************************************/void SendByte(uchar c){

I2DAT=c;I2CON=0XC4; /*清除 SI 位等等 */while(SI==0);

}

Page 30: 第四章   C51 程序设计 -2 实例

/*********************************************** 向有子地址器件发送一个字节数据函数 ***********************************************/bit ISendbyte_1(uchar sla,uchar suba,uchar c){

GetBus(); /*启动总线 */SendByte(sla); /* 发送器件地址 */if(I2STAT!=0X18){

I2CON=0XD4;return(0);

}SendByte(suba); /* 发送器件子地址 */if(I2STAT!=0X28){

I2CON=0XD4;return(0);

}SendByte(c); /* 发送数据 */if(I2STAT!=0X28){

I2CON=0XD4;return(0);

}I2CON=0XD4; /* 结束总线 */return(1);

}

Page 31: 第四章   C51 程序设计 -2 实例

/*******************************************************************向有子地址器件读取多字节数据函数 函数原型 : bit ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);功能 : 从启动总线到发送地址子地址 , 读数据结束总线的全过程 , 从器件 地址 sla 子地址 suba 读出的内容放入 s 指向的存储区读 no 个字节 如果返回 1 表示操作成功否则操作有误 ********************************************************************/bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no){

uchar i;GetBus(); /*启动总线 */SendByte(sla); /* 发送器件地址 */if(I2STAT!=0X18){

I2CON=0XD4;return(0);

}SendByte(suba); /* 发送器件子地址 */if(I2STAT!=0X28){

I2CON=0XD4;return(0);

}I2CON=0XE4; /*重新启动总线 */

while(SI==0);SendByte(sla+1);if(I2STAT!=0X40){

I2CON=0XD4;return(0);

}

Page 32: 第四章   C51 程序设计 -2 实例

for(i=0;i<no-1;i++){

I2CON=0XC4; /* 接收一字节数据并发送应答位 */while(SI==0);if(I2STAT!=0X50){

I2CON=0XD4;return(0);

}*s=I2DAT; /* 读取数据 */s++;

}I2CON=0XC0; /* 接收最后一字节数据并发送非应答位 */while(SI==0);*s=I2DAT;I2CON=0XD4; /* 结束总线 */return(1);}

Page 33: 第四章   C51 程序设计 -2 实例

RS232C/RS485

电子工业协会( EIA )公布的 RS-232C 是用得最多的一种串行通信标准,它是从远程通信标准中导出来的,是使用于数据终端设备( DTE )和数据通信设备( DCE )之间的接口。该标准除包括物理指标外,还包括表明按位串行传送时的电气指标。

Page 34: 第四章   C51 程序设计 -2 实例

RS-232C 电气特性 在电气性能方面, RS-232C 使用负逻辑。逻辑“ 1” 电平是在 -5V ~ -15V范围内,逻辑“ 0” 电平是在 +5V ~ +15V范围内。 标准要求 RS-232C 接收器必须能够识别 +3V 以上的信号作为逻辑“ 0” , -3V 以下的信号作为逻辑“ 1” ,即有 2V 的噪声容限。

RS-232C 的主要电气特性见下表。最大电缆长度 15m

最大数据传输率 20KB/s

驱动器输出电压(开路) ± 25V (最大) 驱动器输出电压(满载) ± 5 ~±25V ( 最大

驱动器输出电阻 300Ω(最小) 驱动器输出短路电流 ± 500mA

接收器输入电阻 3 ~ 7kΩ

接收器输入门限电压值 -3 ~ +3V (最大) 接收器输入电压 -25 ~ +25V (最大)

Page 35: 第四章   C51 程序设计 -2 实例

RS-232C 数据传送格式 RS-232C 的数据传送格式是位串行方式,传输数据的格式如下

图所示,这是微处理机应用系统中最通用的格式。数据的连续传送由最低有效数字位开始,以奇偶校验位作结束。

RS-485 标准 : 由 RS-232C 的电气特性表可知,若不采用调制解调器,其传输距离很短,且最大数据传输率也受到限制。

因此, EIA又公布了能够适合于远距离传输的 RS-485 标准。 RS485 用差分接收器接收信号电压,差分信号的抗噪声能力强。

Page 36: 第四章   C51 程序设计 -2 实例

特 性 RS-422 、 RS-485

最大电缆长度 1200m

最大数据传输率 10MB/s

驱动器输出电压(开路) 6V (最大)输出端之间

驱动器输出电压(满载) 2V (最小)输出端之间

驱动器输出短路电流 ± 150mA (最大)

接收器输入电阻 大于等于 4kΩ

接收器输入门限电压值 -0.2 ~ +0.2V( 最大 )

接收器输入电压 -12V ~ +12V (最大)

当采用 +5V 电源供电时, RS-485 信号定义如下:若差分电压信号为- 2500 ~- 200mV 时,为逻辑“ 0” ;若差分电压信号为+ 2500 ~+ 200mV 时,为逻辑“ 1” ;

Page 37: 第四章   C51 程序设计 -2 实例

MAX485主要特征: 采用单一电源 +5 V 工作,额定电流为 300 μA ,采用半双工通讯方式。

完成将 TTL 电平转换为 RS-485 电平的功能。 内部含有一个驱动器和接收器。 RO和 DI 端分别为接收器的输出和驱动

器的输入端,与单片机连接时只需分别与单片机的 RXD 和 TXD 相连即可;/RE 和 DE 端分别为接收和发送的使能端,当 /RE 为逻辑 0时,器件处于接收状态;当 DE为逻辑 1时,器件处于发送状态,因为 MAX485 工作在半双工状态,所以只需用单片机的一个管脚控制这两个引脚即可;

A 端和 B端分别为接收和发送的差分信号端 ,当 A引脚的电平高于 B时,代表发送的数据为 1;当 A的电平低于 B端时,代表发送的数据为 0。

与单片机连接时,只需要一个信号控制 MAX485 的接收和发送即可。同时将 A和 B端之间加匹配电阻,一般可选 100Ω的电阻。

Page 38: 第四章   C51 程序设计 -2 实例

MAX485芯片硬件电路图

Page 39: 第四章   C51 程序设计 -2 实例

示例程序void init_uart(void) // 串行口初始化 {

PCON = 0; // Set PCON register, clear SMOD0 and SMOD1 bits/*initiate uart0*/T2MOD = 0; // T2OE=0;DCEN=0;S0CON = 0x50; // uart 0 in mode 1 (8 bit), REN=1 RCAP2H= 0xff; //ffb8: 9600 Bds at 11.059MHzRCAP2L= 0xb8; //ffdc: 19200 Bds at 11.059MHzTCLK=1; //T2 overflow as the baud rate generator for uart0 transmit RCLK=1; //T2 overflow as the baud rate generator for uart0 receiveEXEN2=0; //ignore events on T2EX C_T2=0; //timer modeTR2=1; //timer2 runES0R = 1 ; // 开放 UART0 接收中断 EA = 1; // Enable global interrupt UART1_CONTROL=R1_ENABLE;//enable UART1 receive(in max485)UART0_CONTROL=R0_ENABLE;//enable UART0 receive(in max485)

}

Page 40: 第四章   C51 程序设计 -2 实例

void respond_PLC_uart0(void) // 单片机与 PLC进行 485 通信{

uchar i=0;if((ID_num%2)==0){

ID_num_send=ID_num/2;}else if((ID_num%2)==1){

ID_num_send=(ID_num+1)/2;}

ReCommand[0] = '*'; // 设置起始位、从机地址、终止位ReCommand[1] = ID_num_send; // 地址

if(flag_alert_LM==1){

ReCommand[2] = 0x01; //亮度报警信息 }else{

ReCommand[2] = 0x0; //正常 }

Page 41: 第四章   C51 程序设计 -2 实例

ReCommand[3]=tm_send[1]; // 温度值 ReCommand[4]=tm_send[0];ReCommand[5]=lumin_buf[2];ReCommand[6]=lumin_buf[1];ReCommand[7]=lumin_buf[0];ReCommand[9] = '#'; // 结束位if((MASTER==0)&&(SPARE==1)){

ReCommand[8]=0x0;// 主灯工作 }else if((SPARE==0)&&(MASTER==1)){

ReCommand[8]=0x01;// 备灯工作 }

ES0R = 0 ; //关闭 UART0 接收中断 UART0_CONTROL=T0_ENABLE; // 发送使能 for(i=0;i<10;i++){

S0BUF=ReCommand[i];while(TI_0==0)

feed_watchdog();TI_0=0;

}UART0_CONTROL=R0_ENABLE;// 接收使能 _nop_();_nop_();_nop_();_nop_();ES0R = 1 ; // 开放 UART0 接收中断

}

Page 42: 第四章   C51 程序设计 -2 实例

/******** Uart0 receive interrut****************/void IntUart0Rx( void ) interrupt 4{

RI_0=0; //清除接收标志 if(S0BUF == '@'){

Command[0]=S0BUF;UartCount =0;

}else if (S0BUF == '$'){

Command[3]=S0BUF;UartCount =0;

}else if (UartCount < 3){

UartCount++;Command[UartCount]= S0BUF;

}else

UartCount =0;}

Page 43: 第四章   C51 程序设计 -2 实例

SPI 总线: 由同步串行外设接口 SPI 构成的串行总线是一种三线同步总线。总线上

可以连接多个可以作为主机的微控制器 MCU 及装有 SPI 接口的 I/O设备如液晶驱动、 A/D 转换等外设。

SPI 是全双工的,即主机在发送的同时也可以在接收数据,传送的速率由主机编程决定;时钟的极性和相位也是可选择的,具体的约定由设计人员根据总线上各设备接口的功能决定。

Page 44: 第四章   C51 程序设计 -2 实例

SPI 具有四种工作模式,取决于时钟极性( CPOL )和时钟相位( CPHA ),使用的最为广泛的是 SPI0 和 SPI3 方式。

SPI 模式 CPOL CPHA

0 0 0

1 0 1

2 1 0

3 1 1

Page 45: 第四章   C51 程序设计 -2 实例

数据在时钟信号的上升沿锁存,下降沿变化,高位在前,低位在后

Page 46: 第四章   C51 程序设计 -2 实例
Page 47: 第四章   C51 程序设计 -2 实例

//-----------------------------------------------------------------------------// SPI_defs.h//-----------------------------------------------------------------------------//// This file defines the pins used for the SPI device.// The SPI device is mapped to pins P0.0 - P0.3, but can be modified to map to // any of the available GPIO pins on the device.//

#ifndef SPI_DEFS

#define SPI_DEFS

sbit MOSI = P0^0; // Master Out / Slave In (output)sbit MISO = P0^1; // Master In / Slave Out (input)sbit SCK = P0^2; // Serial Clock (output)sbit NSS = P0^3; // Slave Select (output to chip select)

#endif

Page 48: 第四章   C51 程序设计 -2 实例

// SPI_Transfer mode 0// Simultaneously transmits and receives one byte <SPI_byte> using// the SPI protocol. SCK is idle-low, and bits are latched on SCK rising.

char SPI_Transfer (char SPI_byte){ unsigned char SPI_count; // counter for SPI transaction SCK = 0; for (SPI_count = 8; SPI_count > 0; SPI_count--) // single byte SPI loop { MOSI = SPI_byte & 0x80; // put current outgoing bit on MOSI SPI_byte = SPI_byte << 1; // shift next bit into MSB SCK = 0x01; // set SCK high

SPI_byte |= MISO; // capture current bit on MISO

SCK = 0x00; // set SCK low }

return (SPI_byte);

} // END SPI_Transfer