所谓的iic,uart时序,spi开发是指什么?难道不是了解这些接口的原理,然后根据原理和时序编写程序么

2016第三届物联网大会
智能后视镜产品方案对接会
中国LED智能照明高峰论坛
第三届·无线通信技术研讨会
第二届·中国IoT大会
ETFo智能安防技术论坛
移入鼠标可放大二维码
SPI接口的工作原理
来源:本站整理
作者:佚名日 23:24
[导读] MAX7456随屏显示(OSD)发生器具有SPI™兼容接口,本应用笔记介绍了SPI接口的工作原理,文中还包含在微控制器内逐位模拟SPI接口的控制器C程序。
MAX7456随屏显示(OSD)发生器具有SPI™兼容接口,本应用笔记介绍了SPI接口的工作原理,文中还包含在微控制器内逐位模拟SPI接口的控制器C程序。
MAX7456串行接口
MAX7456单通道单色随屏显示(OSD)发生器预装了256个字符和图形,并可通过SPI接口在线编程。通过SPI兼容串行接口可以设置工作模式、显示存储器以及字符存储器。状态(STAT)寄存器、显示存储器数据输出(DMDO)寄存器和字符存储器数据输出(CMDO)寄存器都可读,可以对其进行写操作和读操作。关于MAX7456寄存器及存储器结构的详细信息请参考数据资料和应用笔记4117,"使用MAX7456存储器和评估板文件生成定制字符和图形"。支持高达10MHz接口时钟(SCLK)。图1为写数据时序,图2是从器件读数据的时序。写寄存器时,拉低/CS可使能串行接口。在SCLK的上升沿从SDIN读取数据。当/CS变为高电平时,数据锁存到输入寄存器。如果传输过程中/CS变高,程序终止(即数据不写入寄存器)。/CS变低之后,器件等待从SDIN读入第一个字节,以确定正在执行的数据传输类型。读寄存器时,如上文所述,拉低/CS。地址在SCLK的上升沿锁入SDIN。然后数据在SCLK的下降沿从SDOUT输出。SPI命令长度为16位:最高8位(MSB)代表寄存器地址,最低8位(LSB)代表数据(图1和2)。这种格式有两个例外:
自动递增写模式,用于访问显示存储器,是一个8位操作(图3)。写数据前必须写入起始地址。对显示存储器执行自动递增写命令时,8位地址由内部产生,串口只需8位数据,如图3所示。
从显示存储器读字符数据时,若处于16位工作模式,应该是24位(8位地址+16位数据)。
执行读操作时,只需要8位地址,如图2所示。图1. 写操作图2. 读操作图3. 自动递增写操作
下文给出的C程序已针对MAXQ2000微控制器进行了编译,用于MAX7456评估(EV)板。本文给出了完整的程序例程。程序是自述文档,几乎没有附加说明。C程序可从以下文件获得:spi.c和MAX7456.h。以下程序使用了SPI协议的标准定义,MAXQ2000处理器为SPI主机,MAX7456是SPI从器件。CS与MAX7456数据资料中的定义相同。SDIN对应于MOSI (主机出从器件入)。SDOUT对应于MOSI (主机入从器件出)。SCLK对应于CK。前缀SPI_用于全部程序。
下文所示数据结构可直接或逐位读写数据,用于独立访问SPI端口。C++和一些较新的C编译器支持位字段联合/结构语句)。 /* Port 5 Output Register */
__no_init volatile __io union
unsigned char PO5;
unsigned char bit0
unsigned char bit1
unsigned char bit2
unsigned char bit3
unsigned char bit4
unsigned char bit5
unsigned char bit6
unsigned char bit7
} PO5_
上述代码将一个单字节赋值给PO5,这是微控制器输出端口的地址。然后将另一个字节赋值给相同的可以逐位访问的存储器地址。因此,可用以下命令直接对该端口进行寻址:PO5 = 0x10;或用以下命令逐位读写:PO5_bit.bit4 = 1;如果该程序用于其它处理器,该结构需要重新编写。如果采用不支持位字段宽度的老式C编译器,可用位布尔运算设置及清除位:/* Portable bit-set and bit-clear macros. */
#define BIT_SET(sfr,bitmask) sfr |= (bitmask)
#define BIT_CLR(sfr,bitmask) sfr &=~ (bitmask)
#define BIT0 0x01
#define BIT1 0x02
#define BIT2 0x04
#define BIT3 0x08
#define BIT4 0x10
#define BIT5 0x20
#define BIT6 0x40
#define BIT7 0x80
example: BIT_SET(PO5,BIT0); BIT_CLR(PO5,BIT6);
以下是一个简单的编程技巧,使程序更容易移植:用宏定义控制器引脚排列,如下所示。 #define SPI_CS
PO5_bit.bit4
// PO5_bit.bit4 = active-low CS—chip select
#define SPI_MOSI
PO5_bit.bit5
// PO5_bit.bit5 = MOSI—master out slave in,
// data to MAX7456
#define SPI_MISO
PI5_bit.bit7
// PO5_bit.bit7 = MISO—master in slave out,
// data from MAX7456
#define SPI_CK
PO5_bit.bit6
// PO5_bit.bit6 = SCK - SPI clock
用以上宏和数据结构可以单独置位及复位每个IO口,命令如下:SPI_CS = 1;改变宏时相应引脚也将改变,将上述代码用于其它设计时,如果SPI口引脚排列不同,或为了实现更理想的PCB布局而对引脚进行重新排列,上述程序非常有用。
单字节写操作程序
单字节写操作(图1)程序如下所示。如果可以保证在程序入口处的/CS和CK线状态正确,可以去掉前两条命令。程序首先发送地址,然后发送数据。进行两次循环。采用单循环及16位数据存储可以简化程序。在MAXQ2000微控制器中执行16位“int”所占用的时间比执行8位“char”长,因此需进行权衡考虑。 /*********************************************
* spiWriteReg
* Writes to an 8-bit register with the SPI port
************************************************************/
void spiWriteReg(const unsigned char regAddr, const unsigned char regData)
unsigned char SPIC
// Counter used to clock out the data
unsigned char SPID
// Define a data structure for the SPI data
SPI_CS = 1;
// Make sure we start with active-low CS high
SPI_CK = 0;
// and CK low
SPIData = regA
// Preload the data to be sent with Address
SPI_CS = 0;
// Set active-low CS low to start the SPI cycle
// Although SPIData could be implemented as an "int",
// resulting in one
// loop, the routines run faster when two loops
// are implemented with
// SPIData implemented as two "char"s.
for (SPICount = 0; SPICount & 8; SPICount++)
// Prepare to clock out the Address byte
if (SPIData & 0x80)
// Check for a 1
SPI_MOSI = 1;
// and set the MOSI line appropriately
SPI_MOSI = 0;
SPI_CK = 1;
// Toggle the clock line
SPI_CK = 0;
SPIData &&= 1;
// Rotate to get the next bit
// and loop back to send the next bit
// Repeat for the Data byte
SPIData = regD
// Preload the data to be sent with Data
for (SPICount = 0; SPICount & 8; SPICount++)
if (SPIData & 0x80)
SPI_MOSI = 1;
SPI_MOSI = 0;
SPI_CK = 1;
SPI_CK = 0;
SPIData &&= 1;
SPI_CS = 1;
SPI_MOSI = 0;
读字节操作程序
读字节操作(图2)程序如下所示,与上述程序类似。首先发送地址,然后发送时钟从MISO读回数据。 /*********************************************
* spiReadReg
* Reads an 8-bit register with the SPI port.
* Data is returned.
*******************************************************/
unsigned char spiReadReg (const unsigned char regAddr)
unsigned char SPIC
// Counter used to clock out the data
unsigned char SPID
SPI_CS = 1;
// Make sure we start with active-low CS high
SPI_CK = 0;
// and CK low
SPIData = regA
// Preload the data to be sent with Address and Data
SPI_CS = 0;
// Set active-low CS low to start the SPI cycle
for (SPICount = 0; SPICount & 8; SPICount++)
// Prepare to clock out the Address and Data
if (SPIData & 0x80)
SPI_MOSI = 1;
SPI_MOSI = 0;
SPI_CK = 1;
SPI_CK = 0;
SPIData &&= 1;
// and loop back to send the next bit
SPI_MOSI = 0;
// Reset the MOSI data line
SPIData = 0;
for (SPICount = 0; SPICount & 8; SPICount++)
// Prepare to clock in the data to be read
SPIData &&=1;
// Rotate the data
SPI_CK = 1;
// Raise the clock to clock the data out of the MAX7456
SPIData += SPI_MISO;
// Read the data bit
SPI_CK = 0;
// Drop the clock ready for the next bit
// and loop back
SPI_CS = 1;
// Raise CS
return ((unsigned char)SPIData);
// Finally return the read data
自动递增模式下的写字节操作程序
自动递增模式下的写字节操作(图3)程序如下所示,与和上述单字节写程序类似。首先发送地址,然后发送时钟从MISO读回数据。 /***********************************************
* spiWriteRegAutoIncr
* Writes to an 8-bit register with the SPI port using the MAX7456's autoincrement mode
*************************************************/
void spiWriteRegAutoIncr(const unsigned char regData)
unsigned char SPIC
// Counter used to clock out the data
unsigned char SPID
// Define a data structure for the SPI data.
SPI_CS = 1;
// Make sure we start with active-low CS high
SPI_CK = 0;
// and CK low
SPIData = regD
// Preload the data to be sent with Address and Data
SPI_CS = 0;
// Set active-low CS low to start the SPI cycle
for (SPICount = 0; SPICount & 8; SPICount++)
// Prepare to clock out the Address and Data
if (SPIData & 0x80)
SPI_MOSI = 1;
SPI_MOSI = 0;
SPI_CK = 1;
SPI_CK = 0;
SPIData &&= 1;
// and loop back to send the next bit
SPI_MOSI = 0;
// Reset the MOSI data line
自动递增模式下写显示存储器的程序
自动递增模式下写显示存储器的程序如下,程序使用称为 "data"的全局变量数组。定义如下: extern volatile unsigned char data[DATA_BUF_LENGTH];
DATA_BUF_LENGTH = 968
调用程序时,data[]包含显示存储器内容,格式如下: data[0] = ignored (contains a command byte used by the EV kit GUI software)
data[1] = character byte 1
data[2] = attribute byte 1
data[3] = character byte 2
data[4] = attribute byte 2
自动递增模式通过写0xFF结束,所以该模式下不能向显示寄存器写0xFF。如果需要写OxFF,可以采用单字节写指令。 /*************************************************
* spiWriteCM
* Writes to the Display Memory (960 bytes) from "data" extern.
* 960 = 16 rows × 30 columns × 2 planes {char vs. attr} screen-position-indexed memory
*****************************************************/
void spiWriteCM()
// On entry: global data[1..960]
// contains char+attr bytes
// (optionally terminated by 0xFF data)
// First, write data[1,3,5,...] C
// MAX7456 WriteReg(0x05,0x41)
// "Character Memory Address High";
// 0x01:character memory address msb
volatile unsigned int Index = 0x0001;
// Index for lookup into
// data[1..960]
spiWriteReg(DM_ADDRH_WRITE,0x00);
// initialise the Display Memory high-byte
spiWriteReg(DM_ADDRL_WRITE,0x00);
// and the low-byte
spiWriteReg(DM_MODE_WRITE ,0x41);
// MAX7456 WriteReg(0x04,0x41) "Display Memory Mode";
// 0x40:Perform 8- 0x01:AutoIncrement
// Loop to write the character data
if (data[Index] == 0xFF) {
// Check for the break character
// and finish if found
spiWriteRegAutoIncr(data[Index]);
// Write the character
Index += 2;
// Increment the index to the next character,
// skipping over the attribute
} while(Index & 0x03C1);
// 0x03C1 = 961
// and loop back to send the next character
spiWriteRegAutoIncr(0xFF);
// Write the "escape character" to end AutoIncrement
spiWriteReg(DM_ADDRH_WRITE,0x02);
// Second, write data[2,4,6,...]
// A MAX7456
// WriteReg(0x05,0x41)
// "Character Memory Address High";
// 0x02:A 0x01:character memory address
spiWriteReg(DM_ADDRL_WRITE,0x00);
spiWriteReg(DM_MODE_WRITE,0x41);
// MAX7456 WriteReg(0x04,0x41) "Character Memory
// Mode"; 0x40:Perform 8- 0x01:Auto-
// Increment
Index = 0x0002;
if (data[Index] == 0xFF)
spiWriteRegAutoIncr(data[Index]);
Index += 2;
} while(Index & 0x03C1);
spiWriteRegAutoIncr(0xFF);
写字符存储器程序
向字符存储器写一个字符的程序如下,每个字符占用18行,每行12像素,共216像素。由于每个字节定义4个像素,因此定义每一个字符需要54字节。字符数据位于程序入口处的data[] (与上述写显示存储器的程序类似)。写字符存储器时需要进行一些附加说明,存储器为非易失,因此,写存储器大约需要12ms,由MAX7456执行。只有完整的54字节字符才可以写入字符存储器。该器件包含一个54字节映射存储器。首先把需要写入的字符数据写入映射存储器,然后器件将该数据装载到NVM字符存储器。用来写字符存储器的寄存器有以下几种:
字符存储器模式 = 0x08。向寄存器写0xA0,使器件把映射存储器的内容装载到NVM字符存储器。
字符存储器地址高位 = 0x09。包括了即将写入字符的地址。
字符存储器地址低位 = 0x0A。
字符存储器数据输入 = 0x0B。
Status = 0xA0,读取该寄存器以决定何时可以写入字符存储器。
在程序入口处,data[1]包括即将写入字符的地址,data[2...54]包括字符数据。向NVM字符存储器写字符时,首先写字符地址。然后将每个字节写入映射存储器。写映射存储器时没有自动递增模式,所以每次写操作必须写入映射存储器地址。向字符存储器模式寄存器写0xA0,可以把映射存储器的内容装载到NVM字符存储器。然后器件将状态寄存器第5位置高,表明不能写入字符存储器。完成后,器件将该位复位至低。数据从映射存储器移向字符存储器时不能写映射存储器。为了避免出现显示器闪烁,在写字符存储器之前程序禁止了OSD。 /****************************************
* spiWriteFM
* Writes to the Character Memory (54 bytes) from "data" extern
******************************************/
void spiWriteFM()
unsigned char I
spiWriteReg(VIDEO_MODE_0_WRITE,spiReadReg
(VIDEO_MODE_0_READ) & 0xF7);
// Clear bit 0x08 to DISABLE the OSD display
spiWriteReg(FM_ADDRH_WRITE,data[1]);
// Write the address of the character to be written
// MAX7456 glyph tile definition
// length = 0x36 = 54 bytes
// MAX7456 64-byte Shadow RAM accessed
// through
FM_DATA_.. FM_ADDR.. contains a single
// character/glyph-tile shape
for(Index = 0x00; Index & 0x36; Index++)
spiWriteReg(FM_ADDRL_WRITE,Index);
// Write the address within the shadow RAM
spiWriteReg(FM_DATA_IN_WRITE,data[Index + 2]);
// Write the data to the shadow RAM
spiWriteReg(FM_MODE_WRITE, 0xA0);
// MAX7456 "Font Memory Mode" write 0xA0 triggers
// copy from 64-byte Shadow RAM to NV array.
while ((spiReadReg(STATUS_READ) & 0x20) != 0x00);
// Wait while NV Memory status is BUSY
// MAX status bit 0x20: NV Memory Status
// Busy/~Ready
MAX7456头文件
下面列出了MAX7456的头文件,以下代码决定了器件的寄存器映射。 /**********************************************
* spiWriteRegAutoIncr
* Writes to an 8-bit register with the SPI port by using the MAX7456's autoincrement mode
*******************************************/
// MAX7456 VIDEO_MODE_0 register
#define VIDEO_MODE_0_WRITE
#define VIDEO_MODE_0_READ
#define VIDEO_MODE_0_40_PAL
#define VIDEO_MODE_0_20_NoAutoSync
#define VIDEO_MODE_0_10_SyncInt
#define VIDEO_MODE_0_08_EnOSD
#define VIDEO_MODE_0_04_UpdateVsync
#define VIDEO_MODE_0_02_Reset
#define VIDEO_MODE_0_01_EnVideo
// VIDEO MODE 0 bitmap
#define NTSC
#define PAL
#define AUTO_SYNC
#define EXT_SYNC
#define INT_SYNC
#define OSD_EN
#define VERT_SYNC_IMM
#define VERT_SYNC_VSYNC
#define SW_RESET
#define BUF_EN
#define BUF_DI
// MAX7456 VIDEO_MODE_1 register
#define VIDEO_MODE_1_WRITE
#define VIDEO_MODE_1_READ
// MAX7456 DM_MODE register
#define DM_MODE_WRITE
#define DM_MODE_READ
// MAX7456 DM_ADDRH register
#define DM_ADDRH_WRITE
#define DM_ADDRH_READ
// MAX7456 DM_ADDRL register
#define DM_ADDRL_WRITE
#define DM_ADDRL_READ
// MAX7456 DM_CODE_IN register
#define DM_CODE_IN_WRITE
#define DM_CODE_IN_READ
// MAX7456 DM_CODE_OUT register
#define DM_CODE_OUT_READ
// MAX7456 FM_MODE register
#define FM_MODE_WRITE
#define FM_MODE_READ
// MAX7456 FM_ADDRH register
#define FM_ADDRH_WRITE
#define FM_ADDRH_READ
// MAX7456 FM_ADDRL register
#define FM_ADDRL_WRITE
#define FM_ADDRL_READ
// MAX7456 FM_DATA_IN register
#define FM_DATA_IN_WRITE
#define FM_DATA_IN_READ
// MAX7456 FM_DATA_OUT register
#define FM_DATA_OUT_READ
// MAX7456 STATUS register
#define STATUS_READ
#define STATUS_40_RESET_BUSY
#define STATUS_20_NVRAM_BUSY
#define STATUS_04_LOSS_OF_SYNC
#define STATUS_02_PAL_DETECTED
#define STATUS_01_NTSC_DETECTED
// MAX7456 requires clearing OSD Black Level
// register bit 0x10 after reset
#define OSDBL_WR
#define OSDBL_RD
#define OSDBL_10_DisableAutoBlackLevel
结论和性能
MAX7456评估板采用工作在20MHz时钟的MAXQ2000微控制器,该微控制器包含内部硬件SPI控制器。因此,MAX7456的SPI端口可以全速工作。上述软件SPI程序工作速度低于硬件控制器。不过针对客户缺少硬件SPI端口的工作环境,程序已优化至最简。
SPI是Motorola, Inc.的商标。
MAX7456相关文章
MAX7456相关下载
显示相关文章
显示相关下载
技术交流、积极发言! 发表评请遵守相关规定。
来自NI(美国国家仪器公司,National Instruments)中国射频与无线通信市场开发经理姚远在第六届EEVIA年度中国ICT媒体论坛暨带来了最新的演讲主题《5G产业趋...
在今年的达沃斯会议上,许多科技企业的CEO讨论了AI对人类社会的影响,他们认为,AI不应该替代人类,而是辅助增强人类。世界经济的增长速度并不乐观,...
创新实用技术专题
版权所有 & 深圳华强聚丰电子科技有限公司 上传我的文档
 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
正在努力加载中...
对SPI、IIC、IIS、UART、CAN、SDIO、GPIO的解释
下载积分:30
内容提示:对SPI、IIC、IIS、UART、CAN、SDIO、GPIO的解释
文档格式:PDF|
浏览次数:191|
上传日期: 16:32:27|
文档星级:
该用户还上传了这些文档
对SPI、IIC、IIS、UART、CAN、SDIO、GPIO的解释
官方公共微信【转】SPI、IIC、UART区别 - blakema714的日志 -
电子工程世界-论坛
【转】SPI、IIC、UART区别
已有 6121 次阅读 23:10
|个人分类:
SPI、IIC、UART区别&第一个区别当然是名字:&&&& SPI(Serial Peripheral Interface:串行外设接口);&&&& I2C(INTER IC BUS)&&&& UART(Universal Asynchronous Receiver Transmitter:通用异步收发器)第二,区别在电气信号线上:&&&& SPI总线由三条信号线组成:串行时钟(SCLK)、串行数据输出(SDO)、串行数据输入(SDI)。SPI总线可以实现多个SPI设备互相连接。提供SPI串行时钟的SPI设备为SPI主机或主设备(Master),其他设备为SPI从机或从设备(Slave)。主从设备间可以实现全双工通信,当有多个从设备时,还可以增加一条从设备选择线。&&&& 如果用通用IO口模拟SPI总线,必须要有一个输出口(SDO),一个输入口(SDI),另一个口则视实现的设备类型而定,如果要实现主从设备,则需输入输出口,若只实现主设备,则需输出口即可,若只实现从设备,则只需输入口即可。&&&& I2C总线是双向、两线(SCL、SDA)、串行、多主控(multi-master)接口标准,具有总线仲裁机制,非常适合在器件之间进行近距离、非经常性的数据通信。在它的协议体系中,传输数据时都会带上目的设备的设备地址,因此可以实现设备组网。&&&& 如果用通用IO口模拟I2C总线,并实现双向传输,则需一个输入输出口(SDA),另外还需一个输出口(SCL)。(注:I2C资料了解得比较少,这里的描述可能很不完备)&&&& UART总线是异步串口,因此一般比前两种同步串口的结构要复杂很多,一般由波特率产生器(产生的波特率等于传输波特率的16倍)、UART接收器、UART发送器组成,硬件上由两根线,一根用于发送,一根用于接收。&&&& 显然,如果用通用IO口模拟UART总线,则需一个输入口,一个输出口。第三,从第二点明显可以看出,SPI和UART可以实现全双工,但I2C不行;第四,看看牛人们的意见吧!&&&& wudanyu:I2C线更少,我觉得比UART、SPI更为强大,但是技术上也更加麻烦些,因为I2C需要有双向IO的支持,而且使用上拉电阻,我觉得抗干扰能力较弱,一般用于同一板卡上芯片之间的通信,较少用于远距离通信。SPI实现要简单一些,UART需要固定的波特率,就是说两位数据的间隔要相等,而SPI则无所谓,因为它是有时钟的协议。&&&& quickmouse:I2C的速度比SPI慢一点,协议比SPI复杂一点,但是连线也比标准的SPI要少。posted @
23:00 陈广强 阅读(13) | 评论 (0) | 编辑SPI总线&SPI总线简介&同步外设接口(SPI)是由摩托罗拉公司开发的全双工同步串行总线,该总线大量用在与EEPROM、ADC、FRAM和显示驱动器之类的慢速外设器件通信。SPI(Serial Peripheral Interface)是一种串行同步通讯协议,由一个主设备和一个或多个从设备组成,主设备启动一个与从设备的同步通讯,从而完成数据的交换。SPI 接口由SDI(串行数据输入),SDO(串行数据输出),SCK(串行移位时钟),CS(从使能信号)四种信号构成,CS 决定了唯一的与主设备通信的从设备,如没有CS 信号,则只能存在一个从设备,主设备通过产生移位时钟来发起通讯。通讯时,数据由SDO 输出,SDI 输入,数据在时钟的上升或下降沿由SDO 输出,在紧接着的下降或上升沿由SDI 读入,这样经过8/16 次时钟的改变,完成8/16 位数据的传输。SPI通信该总线通信基于主-从配置。它有以下4个信号:MOSI:主出/从入MISO:主入/从出SCK:串行时钟SS:从属选择芯片上“从属选择”(slave-select)的引脚数决定了可连到总线上的器件数量。&&&&&&& 在SPI传输中,数据是同步进行发送和接收的。数据传输的时钟基于来自主处理器的时钟脉冲,摩托罗拉没有定义任何通用SPI的时钟规范。然而,最常用的时钟设置基于时钟极性(CPOL)和时钟相位(CPHA)两个参数,CPOL定义SPI串行时钟的活动状态,而CPHA定义相对于SO-数据位的时钟相位。CPOL和CPHA的设置决定了数据取样的时钟沿。数据方向和通信速度&&&&&&& SPI传输串行数据时首先传输最高位。波特率可以高达5Mbps,具体速度大小取决于SPI硬件。例如,Xicor公司的SPI串行器件传输速度能达到5MHz。SPI总线接口及时序SPI总线包括1根串行同步时钟信号线以及2根数据线。SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI主模块和与之通信的外设备时钟相位和极性应该一致。SPI主模块和与之通信的外设备时钟相位和极性应该一致。个人理解这句话有2层意思:其一,主设备SPI时钟和极性的配置应该由外设来决定;其二,二者的配置应该保持一致,即主设备的SDO同从设备的SDO配置一致,主设备的SDI同从设备的SDI配置一致。因为主从设备是在SCLK的控制下,同时发送和接收数据,并通过2个双向移位寄存器来交换数据。SPI接口时序如图3、图4所示。SPI是一个环形总线结构,由ss(cs)、sck、sdi、sdo构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换。&&&&& 假设下面的8位寄存器装的是待发送的数据,上升沿发送、下降沿接收、高位先发送。&&&&& 那么第一个上升沿来的时候数据将会是sdo=1;寄存器=0101010x。下降沿到来的时候,sdi上的电平将所存到寄存器中去,那么这时寄存器=0101010sdi,这样在8个时钟脉冲以后,两个寄存器的内容互相交换一次。这样就完成里一个spi时序。&&&&& 例子:&&&&& 假设主机和从机初始化就绪:并且主机的sbuff=0xaa,从机的sbuff=0x55,下面将分步对spi的8个时钟周期的数据情况演示一遍:假设上升沿发送数据脉冲 主机sbuff 从机sbuff sdi sdo&0 &1上 1&1下 &2上 0&2下 &3上 1&3下 &4上 0&4下 &5上 1&5下 &6上 1&6下 &7上 0&7下 &8上 1&8下 这样就完成了两个寄存器8位的交换,上面的上表示上升沿、下表示下降沿,sdi、sdo相对于主机而言的。其中ss引脚作为主机的时候,从机可以把它拉底被动选为从机,作为从机的是时候,可以作为片选脚用。根据以上分析,一个完整的传送周期是16位,即两个字节,因为,首先主机要发送命令过去,然后从机根据主机的名准备数据,主机在下一个8位时钟周期才把数据读回来SPI 总线是Motorola公司推出的三线同步接口,同步串行3线方式进行通信:一条时钟线SCK,一条数据输入线MOSI,一条数据输出线MISO;用于 CPU与各种外围器件进行全双工、同步串行通讯。SPI主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。图3示出SPI总线工作的四种方式,其中使用的最为广泛的是SPI0和SPI3方式(实线表示):图2&& SPI总线四种工作方式SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果 CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI主模块和与之通信的外设音时钟相位和极性应该一致。SPI接口时序如图3、图4所示。二,.SPI功能模块的设计根据功能定义及SPI的工作原理,将整个IP Core分为8个子模块:uC接口模块、时钟分频模块、发送数据FIFO模块、接收数据FIFO模块、状态机模块、发送数据逻辑模块、接收数据逻辑模块以及中断形式模块。深入分析SPI的四种传输协议可以发现,根据一种协议,只要对串行同步时钟进行转换,就能得到其余的三种协议。为了简化设计规定,如果要连续传输多个数据,在两个数据传输之间插入一个串行时钟的空闲等待,这样状态机只需两种状态(空闲和工作)就能正确工作。SPI协议心得SPI接口时钟配置心得:在主设备这边配置SPI接口时钟的时候一定要弄清楚从设备的时钟要求,因为主设备这边的时钟极性和相位都是以从设备为基准的。因此在时钟极性的配置上一定要搞清楚从设备是在时钟的上升沿还是下降沿接收数据,是在时钟的下降沿还是上升沿输出数据。但要注意的是,由于主设备的SDO连接从设备的SDI,从设备的SDO连接主设备的SDI,从设备SDI接收的数据是主设备的SDO发送过来的,主设备SDI接收的数据是从设备SDO发送过来的,所以主设备这边 SPI时钟极性的配置(即SDO的配置)跟从设备的SDI接收数据的极性是相反的,跟从设备SDO发送数据的极性是相同的。下面这段话是Sychip Wlan8100 Module Spec上说的,充分说明了时钟极性是如何配置的:The 81xx module will always input data bits at the rising edge of the clock, and the host will always output data bits on the falling edge of the clock.意思是:主设备在时钟的下降沿发送数据,从设备在时钟的上升沿接收数据。因此主设备这边SPI时钟极性应该配置为下降沿有效。又如,下面这段话是摘自LCD Driver IC SSD1289:SDI is shifted into 8-bit shift register on every rising edge of SCK in the order of data bit 7, data bit 6 …… data bit 0.意思是:从设备SSD1289在时钟的上升沿接收数据,而且是按照从高位到地位的顺序接收数据的。因此主设备的SPI时钟极性同样应该配置为下降沿有效。时钟极性和相位配置正确后,数据才能够被准确的发送和接收。因此应该对照从设备的SPI接口时序或者Spec文档说明来正确配置主设备的时钟。posted @
22:51 陈广强 阅读(24) | 评论 (0) | 编辑IIC一例子&IIC型号&&&& 容量&&&&& 器件/业面寻址字节&&&&&&&&&&&&&&&&&& 可寻址位&&&&&& 模块24C01&& 128B&&&&& (1010)(A2)(A1)(A0)(0或1)&&&& 3&&&&&&&&&&& 128B24C02&& 256B&&&&& (1010)(A2)(A1)(A0)(0或1)&&&& 3&&&&&&&&&&& 256B24C04&& 512B&&&&& (1010)(A2)(A1)(P0)(0或1)&&&& 2&&&&&&&&&&& 2X256B24C08 1024B&&&&& (1010)(A2)(P1)(P0)(0或1)&&&& 1&&&&&&&&&&& 4X256B24C16 2048B&&&&& (1010)(P2)(P1)(P0)(0或1)&&&& 0&&&&&&&&&&& 8X256B解析:IIC总线接口器件24C系列非易失性存储器与89C51接口采用软件模拟IIC。24C系列存储器器件地址统一为1010XXXX,不要问为什么,这是厂家出厂的时候规定好的了。至于24C的引脚功能和89C51的接口我就不多说了,本文的重点主要是如何应用。上面说了,器件的地址字节的高位是1010,那么低4位呢?先说最后一位吧,最后一位为0的时候表示89C51要写数据入存储器,1的时候表示要从存储器读数据。还剩下中三位A2,A1和A0。它们的高低电平取决于24C的A2,A1,A0是接高电平还是接地。A2,A1 和A0有8个组合,因此可以扩展8个相同的器件,根据A2、A1、A0的不同,一样的器件也会有不同的地址。那么是不是每一个24C都可以扩展8个呢?不是的。注意上表,24C01有三个可寻址位,A2,A1,A0,所以可以扩展8个,24C02也一样。而04则只可以扩展4个08只可以扩展2个,16就没有扩展了,只可以挂一片24C16。为什么呢?因为访问24C系列除了访问器件地址外,还要访问器件内的字节的地址。例如24C01,要对其操作,就先选选中它的地址,然后操作第一个字节或其他字节,这些字节也是有地址的,分模块,用一个字节表示,最多可以操作256个字节。24C01和24C02不大于256个字节,对其操作就简单得多了。但24C04,08和16呢?他们都大于256个字节,怎么办?分模块。注意到上表的P0,P1,P3没有?把04分成两个模块,2X256B,08四个模块,16就八个模块。究竟怎么模块操作呢?拿24C08为例,有A2 P1 P0。A2只可以0或1,所以只能扩展2个24C08,其内有4个256字节的模块,要操作哪个模块取决于P1,P0的组合。例如,24C08的地址字节为1010000X第一个字节地址为0,第256个地址为255,如果地址字节是1010001X,那么第256个字节的地址为0,第512个字节的地址为255。就如此。&&& 再用24C08举例说明如何扩展,当两个24C08的A2脚分别接高电平和地的时候,就可以了,这样就扩展了,他们的器件地址分别是1010000X和1010100X。当要读第一个(A2接地)&& 24C08的的第一个模块的数据时候,单片机先发送地址字节;当要把数据写进第二个(A2接高电平)24C08的第二个模块的时候,应发送地址字节。&&& 不再说了,再说我疯了,看程序吧。这是对24C16操作的例子。*/&复制内容到剪贴板&代码:#include &reg51.h&/* 全局符号定义 */#define WRITE 0xA0&&&&&&&&&&&&&&&&&&&&&&& /* 定义24C016的器件地址SLA和方向位W */#define READ 0xA1&&&&&&&&&&&&&&&&&&&&&&& /* 定义24C04的器件地址SLA和方向位R */#define BLOCK_SIZE&&& 100&&&&&&&&&&&&&&&&& /* 定义指定字节个数 */#define uchar unsigned char#define HIGH 1#define LOW 0#define FALSE 0#define TRUE ~FALSEsbit SCL&&&&&&&&&&&&&&& =P3^4; //T0&&&&&&&&sbit SDA&&&&&&&&&&&&&&& =P3^5; //T1&&&&&&&uchar xdata EAROMImage[BLOCK_SIZE]={0}; /* 在外部RAM中定义发送存储映象单元 */void delayi2c( void ) {&&&&&&& ;}void I_start( void ) {&&&&&&& SCL = HIGH ;&&&&&&& delayi2c() ;&&&&&&& SDA = LOW ;&&&&&&& delayi2c() ;&&&&&&& SCL = LOW ;&&&&&&& delayi2c() ;}void I_stop( void ) {&&&&&&& SDA = LOW ;&&&&&&& delayi2c() ;&&&&&&& SCL = HIGH ;&&&&&&& delayi2c() ;&&&&&&& SDA = HIGH ;&&&&&&& delayi2c() ;&&&&&&& SCL = LOW ;&&&&&&& delayi2c() ;}//初始化void I_init( void ) {&&&&&&& SCL = LOW ;&&&&&&& I_stop() ;}bit I_clock( void ) {&&&&&&&&&&&&&& SCL = HIGH ;&&&&&&& delayi2c() ;&&&&&&& sample = SDA ;&&&&&&& SCL = LOW ;&&&&&&& delayi2c() ;&&&&&&& return ( sample ) ;}//发送8位数据bit I_send( uchar I_data ) {&&&&&&&&&&&&&& /* 发送8位数据 */&&&&&&& for ( i=0 ; i&8 ; i++ ) {&&&&&&&&&&&&&&& SDA = (bit)( I_data & 0x80 ) ;&&&&&&&&&&&&&&& I_data = I_data && 1 ;&&&&&&&&&&&&&&& I_clock() ;&&&&&&& }&&&&&&& /* 请求应答信号ACK */&&&&&&& SDA = HIGH ;&&&&&&& return ( ~I_clock() );}//接受8位数据uchar I_receive( void ) {&&&&&&& uchar I_data = 0 ;&&&&&&&&&&&&&& for ( i=0 ; i&8 ; i++ ) {&&&&&&&&&&&&&&& I_data *= 2 ;&&&&&&&&&&&&&&& if (I_clock()) I_data++ ;&&&&&&& }&&&&&&& return ( I_data ) ;}//应答void I_Ack( void ) {&&&&&&& SDA = LOW;&&&&&&& I_clock();&&&&&&& SDA = HIGH;}void wait_5ms( void ) {&&&&&&&&&&&&&& for ( i=0 ; i&1000 ; i++ )&&&& {&&&&&&&&&&&&&&& ;&&&&&&& }}//向24C04写入器件地址和一个指定的字节地址。bit E_address(uchar page ,uchar Address )&&& {&&&&&&& I_start() ;&&&&&&& if ( I_send( WRITE +page) )&&&&&&&&&&&&&&& return ( I_send( Address ) ) ;&&&&&&& else&&&&&&&&&&&&&&& return ( FALSE ) ;&& }//参数的含义:从第几个模块(不超过3),模块中第几个字节(不超过255)//&&&&&&&&&&& 写到RAM映象的第几个字节和读的长度bit E_read_block(uchar page, uchar addr,uchar arraypoint,uchar longth)&& {&&&&&&&&&&&&&& /* 从地址0开始读取数据 */&&&&&&& if ( E_address(page, addr ) ) {&&&&&&&&&&&&&&& /* 发送重复启动信号 */&&&&&&&&&&&&&&& I_start() ;&&&&&&&&&&&&&&& if ( I_send( READ+page ) ) {&&&&&&&&&&&&&&&&&&&&&&& for ( i=0; i&=i++ )&&&&&&&&&&&&&&& {&&&&&&&&&&&&&&&&& EAROMImage[arraypoint+i] =I_receive();&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if ( i != longth ) I_Ack() ;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& else {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& I_clock() ;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& I_stop() ;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& }&&&&&&&&&&&&&&&&&&&&&&& }&&&&&&&&&&&&&&&&&&&&&&& return ( TRUE ) ;&&&&&&&&&&&&&&& }&&&&&&&&&&&&&&& else {&&&&&&&&&&&&&&&&&&&&&&& I_stop() ;&&&&&&&&&&&&&&&&&&&&&&& return ( FALSE ) ;&&&&&&&&&&&&&&& }&&&&&&& }&&&&&&& else&&&&&&&&&&&&&&& I_stop() ;&&&&&&&&&&&&&&& return ( FALSE ) ;}bit E_write_block(uchar page,uchar addr,uchar arraypoint,uchar longth) {&&&&&&&&&&&&&& for ( i= i&=addr+ i++ ) {&&&&&&&&&&&&&&& if ( E_address(page,i) && I_send( EAROMImage[arraypoint+i-addr] ) ) {&&&&&&&&&&&&&&&&&&&&&&& I_stop() ;&&&&&&&&&&&&&&&&&&&&&&& wait_5ms();&&&&&&&&&&&&&&& }&&&&&&&&&&&&&&& else&&&&&&&&&&&&&&&&&&&&&&& return ( FALSE ) ;&&&&&&& }&&&&&&& return ( TRUE ) ;}//testvoid main() {&&&&&&& EAROMImage[39]=0&&& SCON = 0x5a;&&&&&&&&&&& TMOD = 0x20;&&&& TCON = 0x69;&&&& TH1 = 0&&&&&&&& I_init();&&&&&&&&&&&&&&&&&&&&&&& // I2C 总线初始化&&&&&&&& P1=0xFF;&&&&&&&&&&&&&&& if (E_write_block(0,8,39,1))&&&&&&&&&&&&&&&& P1=0xFE;//p10&&&&&&& else&&&&&&&&&&&&&&&& {}&&&&&&& if (E_read_block(0,8,55,1))&&&&&&&&&&&&&&& {}&&&&&&&& else&&&&&&&&&&&&&&& P1=P1&0xFD;&&&&&&&&&&&&&&& if(EAROMImage[55]==0xfe)&&&&&&&& P1=P1&0x0FB;&&&& while(1);}posted @
22:41 陈广强 阅读(18) | 评论 (0) | 编辑关于IIC总线&I2C(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。I2C总线产生于在80年代,最初为音频和视频设备开发,如今主要在服务器管理中使用,其中包括单个组件状态的通信。例如管理员可对各个组件进行查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。可随时监控内存、硬盘、网络、系统温度等多个参数,增加了系统的安全性,方便了管理。&1 I2C总线特点&I2C总线最主要的优点是其简单性和有效性。由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件。I2C总线的另一个优点是,它支持多主控(multimastering), 其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。&2 I2C总线工作原理&2.1 总线的构成及信号类型&I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率100kbps。各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程中,I2C总线上并接的每一模块电路既是主控器(或被控器),又是发送器(或接收器),这取决于它所要完成的功能。CPU发出的控制信号分为地址码和控制量两部分,地址码用来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对比度、亮度等)及需要调整的量。这样,各控制电路虽然挂在同一条总线上,却彼此独立,互不相关。&I2C总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。结束信号:SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。&应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。&目前有很多半导体集成电路上都集成了I2C接口。带有I2C接口的单片机有:CYGNAL的 C8051F0XX系列,PHILIPSP87LPC7XX系列,MICROCHIP的PIC16C6XX系列等。很多外围器件如存储器、监控芯片等也提供I2C接口。I2C总线的时钟信号&&& 在I2C总线上传送信息时的时钟同步信号是由挂接在SCL时钟线上的所有器件的逻辑“与”完成的。SCL线上由高电平到低电平的跳变将影响到这些器件,一旦某个器件的时钟信号变为低电平,将使SCL线上所有器件开始并保护低电平期。此时,低电平周期短的器件的时钟由低至高的跳变并不影响SCL线的状态,这些器件将进入高电平等待的状态。&&& 当所有器件的时钟信号都变为高电平时,低电平期结束,SCL线被释放返回高电平,即所有的器件都同时开始它们的高电平期。其后,第一个结束高电平期的器件又将SCL线拉成低电平。这样就在SCL线上产生一个同步时钟。可见,时钟低电平时间由时钟低电平期最长的器件决定,而时钟高电平时间由时钟高电平期最短的器件决定。I2C总线的传输协议与数据传送起始和停止条件在数据传送过程中,必须确认数据传送的开始和结束。在I2C总线技术规范中,开始和结束信号(也称启动和停止信号)的定义如图3所示。开始信号:当时钟总线SCL为高电平时,数据线SDA由高电平向低电平跳变,开始传送数据。结束信号:当SCL线为高电平时,SDA线从低电平向高电平跳变,结束传送数据。开始和结束信号都是由主器件产生。在开始信号以后,总线即被认为处于忙状态,其它器件不能再产生开始信号。主器件在结束信号以后退出主器件角色,经过一段时间过,总线被认为是空闲的。图3超始和停止信号图数据格式&&& I2C总线数据传送采用时钟脉冲逐位串行传送方式,在SCL的低电平期间,SDA线上高、低电平能变化,在高电平期间,SDA上数据必须保护稳定,以便接收器采样接收,时序如图4所示。图4 数据传送时序图&&& I2C总线发送器送到SDA线上的每个字节必须为8位长,传送时高位在前,低位在后。与之对应,主器件在SCL线上产生8个脉冲;第9个脉冲低电平期间,发送器释放SDA线,接收器把SDA线拉低,以给出一个接收确认位;第9个脉冲高电平期间,发送器收到这个确认位然后开始下一字节的传送,下一个字节的第一个脉冲低电平期间接收器释放SDA。每个字节需要9个脉冲,每次传送的字节数是不受限制的。&&& I2C总线的数据传送格式是在I2C总线开始信号后,送出的第一字节数据是用来选择从器件地址的,其中前7位为地址码,第8位为方向位(R/W)。方向位为“0”表示发送,即主器件把信息写到所选择的从器件中;方向位为“1”表示主器件将从从器件读信息。格式如下: 1010A2A1A0R/W注:前四位固定为1010。&&& 开始信号后,系统中的各个器件将自己的地址和主器件送到总线上的地址进行比较,如果与主器件发送到总线上的地址一致,则该器件即被主器件寻址的器件,其接收信息还是发送信息则由第8位(R/W)决定。发送完第一个字节后再开始发数据信号。响应&&& 数据传输必须带响应。相关的响应时钟脉冲由主机产生,当主器件发送完一字节的数据后,接着发出对应于SCL线上的一个时钟(ACK)认可位,此时钟内主器件释放SDA线,一字节传送结束,而从器件的响应信号将SDA线拉成低电平,使SDA在该时钟的高电平期间为稳定的低电平。从器件的响应信号结束后,SDA线返回高电平,进入下一个传送周期。&&& 通常被寻址的接收器在接收到的每个字节后必须产生一个响应。当从机不能响应从机地址时,从机必须使数据线保持高电平,主机然后产生一个停止条件终止传输或者产生重复起始条件开始新的传输。如果从机接收器响应了从机地址但是在传输了一段时间后不能接收更多数据字节,主机必须再一次终止传输。这个情况用从机在第一个字节后没有产生响应来表示。从机使数据线保持高电平主机产生一个停止或重复起始条件。完整的数据传送过程如图5所示。图5 完整的数据传送过程&&& I2C总线还具有广播呼叫地址用于寻址总线上所有器件的功能。若一个器件不需要广播呼叫寻址中所提供的任何数据,则可以忽咯该地址不作响应。如果该器件需要广播呼叫寻址中按需提供的数据,则应对地址作出响应,其表现为一个接收器。3 总线基本操作&I2C规程运用主/从双向通讯。器件发送数据到总线上,则定义为发送器,器件接收数据则定义为接收器。主器件和从器件都可以工作于接收和发送状态。总线必须由主器件(通常为微控制器)控制,主器件产生串行时钟(SCL)控制总线的传输方向,并产生起始和停止条件。SDA线上的数据状态仅在SCL为低电平的期间才能改变,SCL为高电平的期间,SDA状态的改变被用来表示起始和停止条件。参见图1。图1 串行总线上的数据传送顺序3.1 控制字节&在起始条件之后,必须是器件的控制字节,其中高四位为器件类型识别符(不同的芯片类型有不同的定义,EEPROM一般应为1010),接着三位为片选,最后一位为读写位,当为1时为读操作,为0时为写操作。如图2所示。图2 控制字节配置3.2 写操作 写操作分为字节写和页面写两种操作,对于页面写根据芯片的一次装载的字节不同有所不同。关于页面写的地址、应答和数据传送的时序参见图3。图3 页面写3.3 读操作读操作有三种基本操作:当前地址读、随机读和顺序读。图4给出的是顺序读的时序图。应当注意的是:最后一个读操作的第9个时钟周期不是“不关心”。为了结束读操作,主机必须在第9个周期间发出停止条件或者在第9个时钟周期内保持SDA为高电平、然后发出停止条件。图4 顺序读4 实例:X24C04与MCS-51单片机软硬件的实现X24C04是XICOR公司的CMOS 4096位串行EEPROM,内部组织成512×8位。16字节页面写。与MCS-51单片机接口如图5所示。由于SDA是漏极开路输出,且可以与任何数目的漏极开路或集电极 开路输出“线或”(wire-Ored)连接。上拉电阻的选择可参考X24C04的数据 手册。下面是通过I2C接口对X24C04进行单字节写操作的例程。流程图及源程序如下:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&图5 X24C04与51单片机接口;名称:BSENT&;描述:写字节&;功能:写一个字节&;调用程序:无&;输入参数:A&;输出参数:无&&&&&& BSEND: MOV R2,#08H ;1字节8位SENDA: CLR P3.2&&& ;&&&&&&&& RLC A&&&&&&&&&&&&& ;左移一位&&&&& MOV P3.3,C&&&&&&&& ;写一位SETB P3.2&DJNZ R2,SENDA&&&&& ;写完8个字节?&CLR P3.2&&&&&&&&&& ;应答信号&SETB P3.3&SETB P3.2&RET图6 流程图5 结束语在I2C总线的应用中应注意的事项总结为以下几点 :&1) 严格按照时序图的要求进行操作,&2) 若与口线上带内部上拉电阻的单片机接口连接,可以不外加上拉电阻。&3) 程序中为配合相应的传输速率,在对口线操作的指令后可用NOP指令加一定的延时。&4) 为了减少意外的干扰信号将EEPROM内的数据改写可用外部写保护引脚(如果有),或者在EEPROM内部没有用的空间写入标志字,每次上电时或复位时做一次检测,判断EEPROM是否被意外改写。&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 关于IIC总线的操作注意事项1、对IIC总线的一次操作完之后,需要等待一段时间才能进行第二次操作。否则是启动不了总线的:)2、在时钟线(SCL)为高电平的时候,一定不能动数据线(SDA)状态,除非是启动或者结束总线posted @
22:19 陈广强 阅读(14) | 评论 (0) | 编辑OC门分析&&&&&& 我们先来说说集电极开路输出的结构。集电极开路输出的结构如图1所示,右边的那个三极管集电极什么都不接,所以叫做集电极开路(左边的三极管为反相之用,使输入为"0"时,输出也为"0")。对于图1,当左端的输入为“0”时,前面的三极管截止(即集电极C跟发射极E之间相当于断开),所以5V电源通过 1K电阻加到右边的三极管上,右边的三极管导通(即相当于一个开关闭合);当左端的输入为“1”时,前面的三极管导通,而后面的三极管截止(相当于开关断开)。  我们将图1简化成图2的样子。图2中的开关受软件控制,“1”时断开,“0”时闭合。很明显可以看出,当开关闭合时,输出直接接地,所以输出电平为0。而当开关断开时,则输出端悬空了,即高阻态。这时电平状态未知,如果后面一个电阻负载(即使很轻的负载)到地,那么输出端的电平就被这个负载拉到低电平了,所以这个电路是不能输出高电平的。&  再看图三。图三中那个1K的电阻即是上拉电阻。如果开关闭合,则有电流从1K电阻及开关上流过,但由于开关闭和时电阻为0(方便我们的讨论,实际情况中开关电阻不为0,另外对于三极管还存在饱和压降),所以在开关上的电压为0,即输出电平为0。如果开关断开,则由于开关电阻为无穷大(同上,不考虑实际中的漏电流),所以流过的电流为0,因此在1K电阻上的压降也为0,所以输出端的电压就是5V了,这样就能输出高电平了。但是这个输出的内阻是比较大的(即1KΩ),如果接一个电阻为R的负载,通过分压计算,就可以算得最后的输出电压为5*R/(R+1000)伏,即5 /(1+1000/R)伏。所以,如果要达到一定的电压的话,R就不能太小。如果R真的太小,而导致输出电压不够的话,那我们只有通过减小那个1K的上拉电阻来增加驱动能力。但是,上拉电阻又不能取得太小,因为当开关闭合时,将产生电流,由于开关能流过的电流是有限的,因此限制了上拉电阻的取值,另外还需要考虑到,当输出低电平时,负载可能还会给提供一部分电流从开关流过,因此要综合这些电流考虑来选择合适的上拉电阻。&  如果我们将一个读数据用的输入端接在输出端,这样就是一个IO口了(51的IO口就是这样的结构,其中P0口内部不带上拉,而其它三个口带内部上拉),当我们要使用输入功能时,只要将输出口设置为1即可,这样就相当于那个开关断开,而对于P0口来说,就是高阻态了。&什么是漏极开路(OD)?  对于漏极开路(OD)输出,跟集电极开路输出是十分类似的。将上面的三极管换成场效应管即可。这样集电极就变成了漏极,OC就变成了OD,原理分析是一样的。&  另一种输出结构是推挽输出。推挽输出的结构就是把上面的上拉电阻也换成一个开关,当要输出高电平时,上面的开关通,下面的开关断;而要输出低电平时,则刚好相反。比起OC或者OD来说,这样的推挽结构高、低电平驱动能力都很强。如果两个输出不同电平的输出口接在一起的话,就会产生很大的电流,有可能将输出口烧坏。而上面说的OC或OD输出则不会有这样的情况,因为上拉电阻提供的电流比较小。如果是推挽输出的要设置为高阻态时,则两个开关必须同时断开(或者在输出口上使用一个传输门),这样可作为输入状态,AVR单片机的一些IO 口就是这种结构。
作者的其他最新日志
评论 ( 个评论)
Powered by

我要回帖

更多关于 uart时序 的文章

 

随机推荐