[置顶] ZigBee研究之旅(四)---CC2530的时钟模块
2013-09-27 21:46
471 查看
CC2530的时钟模块
(cc2530_datasheet节选翻译如下)
******************************************************************
* 作 者:fulinux
* 转载声明:点击链接
******************************************************************
振荡器和时钟
CC2530设备有一个内部系统时钟,或者主时钟。系统时钟源可以是从16MHz RC振荡器或一个32M晶体振荡器中的一个提供。系统时钟源是由CLKCONCMD SRF控制寄存器。
还有一个32KHz的时钟源,来源可以是从RC 振荡器或者32KHz的晶体振荡器中过来,同样是由CLKCONCMD寄存器控制。
CLKCONSTA寄存器是一个制度寄存器,用来获得当前系统时钟的状态。
时钟源可以在一个精度高的晶体振荡器和一个功耗低的RC振荡器中交替选择使用。注意一点:RF的收发操作是要以32MHz的晶体振荡器为时钟源才行。
振荡器
图中给出了时钟系统中可用的时钟源的一个全貌图。
设备中存在的两个高频振荡器:
* 32MHz晶体振荡器
* 16MHz的RC振荡器
32MHz的晶体振荡器启动时间对于某些应用来说可能太长了;因此设备可以先运行在16MHz的RC振荡器中运行直到晶体振荡器稳定后在使用32MHz晶体振荡器。16MHz的RC振
荡器功耗低但是不是很准,所以不能为RF模块提供服务,只能用32MHz的晶体振荡器。
设备中存在的两个低频振荡器:
* 32 KHz晶体振荡器
* 32 KHz RC振荡器
32KHz的XOSC被设计的工作频率频率是32.768KHz并且可以为一些要求时钟准确子系统提供一个稳定的时钟信号。32KHz的RCOSC当校准后可以运行在32.753KHz频率下。校准
只能发生在当32MHz XOSC使能的情况下,可以通过使能SLEEPCMD.OSC32K_CALDIS位来关闭校准。32KHz RC振荡器相对于32KHz XOSC晶体振荡器功耗低,应该用在可以降
低成本情况下。两个振荡器不能同时工作。
系统时钟
系统时钟是由32MHz XOSC或者16MHz RCOSC两个时钟源驱动的。CLKCONCMD.OSC位用来选择系统时钟源。注意:使用RF模块时,32MHz晶体振荡器必须被选上并且运行稳定。
注意:改变CLKCONCMD.OSC位并不能立即导致系统时钟源的改变。当CLKCONSTA.OSC = CLKCONCMD.OSC时时钟源的改变才会发挥作用。这是因为设备在实际改变时钟源之前
需要稳定的时钟。还有就是注意CLKCONCMD.CLKSPD位反应着系统时钟频率,因此是CLKACONCMD.OSC位的镜子。一旦32MHz的XOSC被选中和稳定,例如,当CLKCONSTA.OSC
位从1切换到0时。
注意:从16MHz到32MHz时钟源的改变符合CLKCONCMD.TICKSPD设置。CLKCONCMD.TICKSPD设置的缓慢一些的话,当CLKCONCMD.OSC改变的话会导致实际的时钟源起作用的
时间会很长。当CLKCONCMD.TICKSPD等于000时会获得最快的切换速度。
32KHz的振荡器
默认的或者复位后32KHz RCOSC使能并且被设置作为32KHz的时钟源。其功耗低,但是相对于32KHz晶体振荡器而言精度不高,32KHz时钟源用来驱动睡眠定时器,产生看门狗的滴答值
和作为timer 2计算睡眠定时器的一个闸门。32KHz时钟源被寄存器CLKCONCMD.OSC32K位用来作为选择振荡器。CLKCONCMD.OSC32K寄存器可以在任意时间写入,但是在16MHz RC
振荡器是活跃的系统时钟源之前是不会起作用的。当系统时钟从16MHz改变为32MHz的晶体振荡器(CLKCONCMD.OSC从1到0)一旦32KHz RC振荡器被选中了它的的校验就启动了并且被执行。在校准期间,32MHz晶体振荡器的一个分频量会被使用。32KHzRCOSC振荡器校准后的结果是它会工作在32.753kHz上。32kHz RC振荡器校准时间可能要2ms时间来完成。可以设置SLEEPCMD.OSC32K_CALDIS位设置为1的话,会关闭校准。在校准结束时,会在32KHz时钟源上产生一个额外的脉冲,会导致睡眠定时器增加1。
注意:当切换到32KHz晶体振荡器后和从32KHz晶体振荡器被设置的PM3模式唤醒时,振荡器稳定到准确频率的时间在500 ms以上。睡眠定时器、看门狗定时器和时钟损失探测器在32KHz
晶体振荡器稳定之前不能使用。
振荡器和时钟寄存器
下面是振荡器和时钟寄存器的描述,所有寄存器的位会在进入PM2和PM3时保持不变,除非有异常情况发生。
定时器滴答值产生器
CLKCONCMD.TICKSPD寄存器控制timer1、timer3和timer4的全局预分频。预分频的值设置范围在0.25MHz和32MHz之间。
需要注意的是如果CLKCONCMD.TICKSPD显示的频率高于系统时钟,则在CLKCONSTA.TICKSPD中的实际的预分频值表明是和系统时钟的值是一样的。
数据滞留
在PM2和PM3电源模式中,绝大多数的内部电路关闭了,然而,SRAM中任保留它的内容,内部寄存器的值也会保留。
保留数据的寄存器是CPU的寄存器、外部寄存器和RF寄存器,除非另一些位域值设置的比较特殊。切换到PM2和PM3模式的现象对于软件而已是透明的。
注意在PM3模式下睡眠定时器的值不会保存。
******************************************************************
* 作 者:fulinux
* 转载声明:点击链接,如有不对之处,请指正
******************************************************************
(cc2530_datasheet节选翻译如下)
******************************************************************
* 作 者:fulinux
* 转载声明:点击链接
******************************************************************
振荡器和时钟
CC2530设备有一个内部系统时钟,或者主时钟。系统时钟源可以是从16MHz RC振荡器或一个32M晶体振荡器中的一个提供。系统时钟源是由CLKCONCMD SRF控制寄存器。
还有一个32KHz的时钟源,来源可以是从RC 振荡器或者32KHz的晶体振荡器中过来,同样是由CLKCONCMD寄存器控制。
CLKCONSTA寄存器是一个制度寄存器,用来获得当前系统时钟的状态。
时钟源可以在一个精度高的晶体振荡器和一个功耗低的RC振荡器中交替选择使用。注意一点:RF的收发操作是要以32MHz的晶体振荡器为时钟源才行。
振荡器
图中给出了时钟系统中可用的时钟源的一个全貌图。
设备中存在的两个高频振荡器:
* 32MHz晶体振荡器
* 16MHz的RC振荡器
32MHz的晶体振荡器启动时间对于某些应用来说可能太长了;因此设备可以先运行在16MHz的RC振荡器中运行直到晶体振荡器稳定后在使用32MHz晶体振荡器。16MHz的RC振
荡器功耗低但是不是很准,所以不能为RF模块提供服务,只能用32MHz的晶体振荡器。
设备中存在的两个低频振荡器:
* 32 KHz晶体振荡器
* 32 KHz RC振荡器
32KHz的XOSC被设计的工作频率频率是32.768KHz并且可以为一些要求时钟准确子系统提供一个稳定的时钟信号。32KHz的RCOSC当校准后可以运行在32.753KHz频率下。校准
只能发生在当32MHz XOSC使能的情况下,可以通过使能SLEEPCMD.OSC32K_CALDIS位来关闭校准。32KHz RC振荡器相对于32KHz XOSC晶体振荡器功耗低,应该用在可以降
低成本情况下。两个振荡器不能同时工作。
系统时钟
系统时钟是由32MHz XOSC或者16MHz RCOSC两个时钟源驱动的。CLKCONCMD.OSC位用来选择系统时钟源。注意:使用RF模块时,32MHz晶体振荡器必须被选上并且运行稳定。
注意:改变CLKCONCMD.OSC位并不能立即导致系统时钟源的改变。当CLKCONSTA.OSC = CLKCONCMD.OSC时时钟源的改变才会发挥作用。这是因为设备在实际改变时钟源之前
需要稳定的时钟。还有就是注意CLKCONCMD.CLKSPD位反应着系统时钟频率,因此是CLKACONCMD.OSC位的镜子。一旦32MHz的XOSC被选中和稳定,例如,当CLKCONSTA.OSC
位从1切换到0时。
注意:从16MHz到32MHz时钟源的改变符合CLKCONCMD.TICKSPD设置。CLKCONCMD.TICKSPD设置的缓慢一些的话,当CLKCONCMD.OSC改变的话会导致实际的时钟源起作用的
时间会很长。当CLKCONCMD.TICKSPD等于000时会获得最快的切换速度。
32KHz的振荡器
默认的或者复位后32KHz RCOSC使能并且被设置作为32KHz的时钟源。其功耗低,但是相对于32KHz晶体振荡器而言精度不高,32KHz时钟源用来驱动睡眠定时器,产生看门狗的滴答值
和作为timer 2计算睡眠定时器的一个闸门。32KHz时钟源被寄存器CLKCONCMD.OSC32K位用来作为选择振荡器。CLKCONCMD.OSC32K寄存器可以在任意时间写入,但是在16MHz RC
振荡器是活跃的系统时钟源之前是不会起作用的。当系统时钟从16MHz改变为32MHz的晶体振荡器(CLKCONCMD.OSC从1到0)一旦32KHz RC振荡器被选中了它的的校验就启动了并且被执行。在校准期间,32MHz晶体振荡器的一个分频量会被使用。32KHzRCOSC振荡器校准后的结果是它会工作在32.753kHz上。32kHz RC振荡器校准时间可能要2ms时间来完成。可以设置SLEEPCMD.OSC32K_CALDIS位设置为1的话,会关闭校准。在校准结束时,会在32KHz时钟源上产生一个额外的脉冲,会导致睡眠定时器增加1。
注意:当切换到32KHz晶体振荡器后和从32KHz晶体振荡器被设置的PM3模式唤醒时,振荡器稳定到准确频率的时间在500 ms以上。睡眠定时器、看门狗定时器和时钟损失探测器在32KHz
晶体振荡器稳定之前不能使用。
振荡器和时钟寄存器
下面是振荡器和时钟寄存器的描述,所有寄存器的位会在进入PM2和PM3时保持不变,除非有异常情况发生。
定时器滴答值产生器
CLKCONCMD.TICKSPD寄存器控制timer1、timer3和timer4的全局预分频。预分频的值设置范围在0.25MHz和32MHz之间。
需要注意的是如果CLKCONCMD.TICKSPD显示的频率高于系统时钟,则在CLKCONSTA.TICKSPD中的实际的预分频值表明是和系统时钟的值是一样的。
数据滞留
在PM2和PM3电源模式中,绝大多数的内部电路关闭了,然而,SRAM中任保留它的内容,内部寄存器的值也会保留。
保留数据的寄存器是CPU的寄存器、外部寄存器和RF寄存器,除非另一些位域值设置的比较特殊。切换到PM2和PM3模式的现象对于软件而已是透明的。
注意在PM3模式下睡眠定时器的值不会保存。
******************************************************************
* 作 者:fulinux
* 转载声明:点击链接,如有不对之处,请指正
******************************************************************
/********************************************************************************************************************************************************** * 文 件 名:main.c × * 功 能:实验一 系统时钟源的选择 * * CC2530有1个内部的系统时钟。时钟源可以是1个16MHz的RC振荡器,也可以是1个32MHz的晶体 * 振荡器。时钟控制是通过使用CLKCON特殊功能寄存器来执行的。系统时钟也提供给所有的8051 * 外设。 * * 32MHz晶体振荡器的启动时间对于某些应用而言太长了,因此CC2530可以运行在16MHz RC振荡器 * 直到晶体振荡器稳定。16MHz RC振荡器的功耗要少于晶体振荡器,但是由于它没有晶体振荡器 * 精确,因此它不适用于射频收发器。 * * CLKCONCMD.OSC位被用来选择系统时钟源。注意:要使用射频收发器,32MHz晶体振荡器必须被选择 * 并且稳定。 * * 注意:改变CLKCON.OSC位并不即刻生效。这是因为在实际改变时钟源之前,被选择的时钟源要 * 首先达到稳定。还要注意:CLKCONSTA.CLKSPD位将反映系统时钟频率,因此它是CLKCON.OSC位的 * “镜子”。 * * 当SLEEPSTA.XOSC_STB为1时,表示系统报告32MHz晶体振荡器稳定。然而,这可能并不是实际情况, × 在选择32MHz时钟作为系统时钟源之前,应该等待一个额外的64us的安全时间,可以通过增加一 * 条空指令"NOP"来实现。如果不等待,可能会造成系统崩溃。 * * 未被选择作为系统时钟源的振荡器,通过设置SLEEP.OSC_PD为1(默认状态)将被设置为掉电模式。 * 因此,当32MHz晶体振荡器被选择作为系统时钟源后,16MHz RC振荡器可能被关闭,反之亦然。 * 当SLEEPCMD.OSC_PD为0时,这2个振荡器都被上电并运行。 * 当32MHz晶体振荡器被选择作为系统时钟源并且16MHz RC振荡器也被上电时,根据供电电压和运 * 行温度,16MHZ RC振荡器将被不断校准以确保时钟稳定。当16MHz RC振荡器被选择作为系统时钟 * 源时,该校准不被执行。 * * 本实验将向用户演示选择不同的振荡器作为系统时钟源。本文件中有led闪烁的子程序,用户 * 可以观察在不同系统时钟源下led的闪烁情况。 * * 在hal.h文件中包含了和系统时钟相关的一些宏,用户使用这些宏可以简化对系统时钟的控制, * 提高代码的可读性,本实验中就使用了其中的一些宏。 * * 注 意:本实验可在以下目标板上进行: * * * * * * 版 本:V1.0 **********************************************************************************************************************************************************/ #include "hal.h" #define ON 0x01 //LED状态 #define OFF 0x00 extern void ctrPCA9554LED(UINT8 led,UINT8 operation); extern void PCA9554ledInit(); /************************************************************************************************** * 函数名称:halWait * * 功能描述:延时 * * 参 数:wait - 延时时间 * * 返 回 值:无 **************************************************************************************************/ void halWait(BYTE wait){ UINT32 largeWait; if(wait == 0) {return;} largeWait = ((UINT16) (wait << 7)); largeWait += 114*wait; largeWait = (largeWait >> CLKSPD); while(largeWait--); return; } /************************************************************************************************** * 函数名称:main * * 功能描述:反复选择不同的振荡器作为系统时钟源,并调用led控制程序,闪烁LED灯。 * * 参 数:无 * * 返 回 值:无 **************************************************************************************************/ void main(void) { UINT8 i; PCA9554ledInit(); while(1) { SET_MAIN_CLOCK_SOURCE(CRYSTAL); // 设置系统时钟源为32MHz晶体振荡器(大约用时150us),关闭16MHz RC振荡器 for (i=0;i<10;i++) { ctrPCA9554LED(0,ON); halWait(200); ctrPCA9554LED(0,OFF); halWait(200); } SET_MAIN_CLOCK_SOURCE(RC); // 选择16MHz RC振荡器,关闭32MHz晶体振荡器 PCA9554ledInit(); halWait(200); for (i=0;i<10;i++) { ctrPCA9554LED(1,ON); halWait(200); ctrPCA9554LED(1,OFF); halWait(200); } } }
/********************************************************************************************************** * 文 件 名:iic.C * 功 能:实验二 GPIO控制实验 * 该实验采用CC2530的I/O口(P1.0和P1.1)模拟IIC总线的SCL和SDA,然后通过IIC总线形式控制GPIO扩展芯片 * PCA9554,最后通过扩展的IO来控制LED的亮灭。 * * 硬件连接:将OURS的CC2530RF模块插入到普通电池板或智能电池板上。 * * P1.0 ------ SCL * P1.1 ------ SDA * * 版 本:V1.0 **************************************************************************************************************/ #include "ioCC2530.h" #include "hal_mcu.h" #define SCL P1_0 //IIC时钟线 #define SDA P1_1 //IIC数据线 //定义IO方向控制函数 #define IO_DIR_PORT_PIN(port, pin, dir) \ do { \ if (dir == IO_OUT) \ P##port##DIR |= (0x01<<(pin)); \ else \ P##port##DIR &= ~(0x01<<(pin)); \ }while(0) #define OSC_32KHZ 0x00 //使用外部32K晶体振荡器 //时钟设置函数 #define HAL_BOARD_INIT() \ { \ uint16 i; \ \ SLEEPCMD &= ~OSC_PD; /* 开启 16MHz RC 和32MHz XOSC */ \ while (!(SLEEPSTA & XOSC_STB)); /* 等待 32MHz XOSC 稳定 */ \ asm("NOP"); \ for (i=0; i<504; i++) asm("NOP"); /* 延时63us*/ \ CLKCONCMD = (CLKCONCMD_32MHZ | OSC_32KHZ); /* 设置 32MHz XOSC 和 32K 时钟 */ \ while (CLKCONSTA != (CLKCONCMD_32MHZ | OSC_32KHZ)); /* 等待时钟生效*/ \ SLEEPCMD |= OSC_PD; /* 关闭 16MHz RC */ \ } #define IO_IN 0 //输入 #define IO_OUT 1 //输出 uint8 ack; //应答标志位 uint8 PCA9554ledstate = 0; //所有LED当前状态 /****************************************************************************** * 函数名称:QWait * * 功能描述:1us的延时 * * 参 数:无 * * 返 回 值:无 *****************************************************************************/ void QWait() { asm("NOP");asm("NOP"); asm("NOP");asm("NOP"); asm("NOP");asm("NOP"); asm("NOP");asm("NOP"); asm("NOP");asm("NOP"); asm("NOP"); } /****************************************************************************** * 函数名称:Wait * * 功能描述:ms的延时 * * 参 数:ms - 延时时间 * * 返 回 值:无 *****************************************************************************/ void Wait(unsigned int ms) { unsigned char g,k; while(ms) { for(g=0;g<=167;g++) { for(k=0;k<=48;k++); } ms--; } } /****************************************************************************** * 函数名称:Start_I2c * * 功能描述:启动I2C总线,即发送I2C起始条件. * * 参 数:无 * * 返 回 值:无 *****************************************************************************/ void Start_I2c() { IO_DIR_PORT_PIN(1, 0, IO_OUT); //设置P1.0为输出 IO_DIR_PORT_PIN(1, 1, IO_OUT); //设置P1.1为输出 SDA=1; /*发送起始条件的数据信号*/ asm("NOP"); SCL=1; QWait(); /*起始条件建立时间大于4.7us,延时*/ QWait(); QWait(); QWait(); QWait(); SDA=0; /*发送起始信号*/ QWait(); /* 起始条件锁定时间大于4μs*/ QWait(); QWait(); QWait(); QWait(); SCL=0; /*钳住I2C总线,准备发送或接收数据 */ asm("NOP"); asm("NOP"); } /****************************************************************************** * 函数名称:Stop_I2c * * 功能描述:结束I2C总线,即发送I2C结束条件. * * 参 数:无 * * 返 回 值:无 *****************************************************************************/ void Stop_I2c() { IO_DIR_PORT_PIN(1, 0, IO_OUT); //设置P1.0为输出 IO_DIR_PORT_PIN(1, 1, IO_OUT); //设置P1.1为输出 SDA=0; /*发送结束条件的数据信号*/ asm("NOP"); /*发送结束条件的时钟信号*/ SCL=1; /*结束条件建立时间大于4μs*/ QWait(); QWait(); QWait(); QWait(); QWait(); SDA=1; /*发送I2C总线结束信号*/ QWait(); QWait(); QWait(); QWait(); } /****************************************************************************** * 函数名称:SendByte * * 功能描述:将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 * 此状态位进行操作.(不应答或非应答都使ack=0 假) * 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。 * * 参 数:c - 需发送的数据 * * 返 回 值:无 *****************************************************************************/ void SendByte(uint8 c) { uint8 BitCnt; IO_DIR_PORT_PIN(1, 0, IO_OUT); //设置P1.0为输出 IO_DIR_PORT_PIN(1, 1, IO_OUT); //设置P1.1为输出 for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/ { if((c<<BitCnt)&0x80)SDA=1; /*判断发送位*/ else SDA=0; asm("NOP"); SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/ QWait(); QWait(); /*保证时钟高电平周期大于4μs*/ QWait(); QWait(); QWait(); SCL=0; } QWait(); QWait(); QWait(); SDA=1; /*8位发送完后释放数据线,准备接收应答位*/ asm("NOP"); IO_DIR_PORT_PIN(1, 1, IO_IN); SCL=1; QWait(); QWait(); QWait(); QWait(); if(SDA==1)ack=0; else ack=1; /*判断是否接收到应答信号*/ SCL=0; QWait(); QWait(); IO_DIR_PORT_PIN(1, 1, IO_OUT); } /****************************************************************************** * 函数名称:RcvByte * * 功能描述:用来接收从器件传来的数据,并判断总线错误(不发应答信号), * 发完后请用应答函数。 * * 参 数:无 * * 返 回 值:retc - 从器件传来的数据 *****************************************************************************/ uint8 RcvByte() { uint8 retc; uint8 BitCnt; IO_DIR_PORT_PIN(1, 0, IO_OUT); //设置P1.0为输出 IO_DIR_PORT_PIN(1, 1, IO_OUT); //设置P1.1为输出 retc=0; SDA=1; /*置数据线为输入方式*/ IO_DIR_PORT_PIN(1, 1, IO_IN); for(BitCnt=0;BitCnt<8;BitCnt++) { asm("NOP"); SCL=0; /*置时钟线为低,准备接收数据位*/ QWait(); QWait(); /*时钟低电平周期大于4.7μs*/ QWait(); QWait(); QWait(); SCL=1; /*置时钟线为高使数据线上数据有效*/ QWait(); QWait(); retc=retc<<1; if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */ QWait(); QWait(); } SCL=0; QWait(); QWait(); IO_DIR_PORT_PIN(1, 1, IO_OUT); return(retc); } /****************************************************************************** * 函数名称:Ack_I2c * * 功能描述:主控器进行应答信号,(可以是应答或非应答信号) * * * 参 数:无 * * 返 回 值:无 *****************************************************************************/ void Ack_I2c(uint8 a) { IO_DIR_PORT_PIN(1, 0, IO_OUT); //设置P1.0为输出 IO_DIR_PORT_PIN(1, 1, IO_OUT); //设置P1.1为输出 if(a==0)SDA=0; /*在此发出应答或非应答信号 */ else SDA=1; QWait(); //QWait(); //QWait(); SCL=1; QWait(); QWait(); /*时钟低电平周期大于4μs*/ QWait(); QWait(); QWait(); SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/ QWait(); //QWait(); } /****************************************************************************** * 函数名称:ISendByte * * 功能描述:从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla. * 如果返回1表示操作成功,否则操作有误。 * * * 参 数:sla - 从器件地址 * c - 需发送的数据 * * 返 回 值:0 -- 失败 * 1 -- 成功 *****************************************************************************/ uint8 ISendByte(uint8 sla,uint8 c) { Start_I2c(); /*启动总线*/ SendByte(sla); /*发送器件地址*/ if(ack==0)return(0); SendByte(c); /*发送数据*/ if(ack==0)return(0); Stop_I2c(); /*结束总线*/ return(1); } /****************************************************************************** * 函数名称:ISendStr * * 功能描述:从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件 * 地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。 * 如果返回1表示操作成功,否则操作有误。 * * * 参 数:sla - 从器件地址 * suba - 从器件子地址 * *s - 数据 * no - 数据字节数目 * * 返 回 值:0 -- 失败 * 1 -- 成功 * * 注 意:使用前必须已结束总线。 *****************************************************************************/ uint8 ISendStr(uint8 sla,uint8 suba,uint8 *s,uint8 no) { uint8 i; Start_I2c(); /*启动总线*/ SendByte(sla); /*发送器件地址*/ if(ack==0)return(0); SendByte(suba); /*发送器件子地址*/ if(ack==0)return(0); for(i=0;i<no;i++) { SendByte(*s); /*发送数据*/ if(ack==0)return(0); s++; } Stop_I2c(); /*结束总线*/ return(1); } /****************************************************************************** * 函数名称:IRcvByte * * 功能描述:从启动总线到发送地址,读数据,结束总线的全过程,从器件地 * 址sla,返回值在c. 如果返回1表示操作成功,否则操作有误。 * * * 参 数:sla - 从器件地址 * *c - 需发送的数据 * * 返 回 值:0 -- 失败 * 1 -- 成功 * *注 意:使用前必须已结束总线。 *****************************************************************************/ uint8 IRcvByte(uint8 sla,uint8 *c) { Start_I2c(); /*启动总线*/ SendByte(sla+1); /*发送器件地址*/ //SendByte(sla); if(ack==0)return(0); *c=RcvByte(); /*读取数据*/ Ack_I2c(1); /*发送非就答位*/ Stop_I2c(); /*结束总线*/ return(1); } /****************************************************************************** * 函数名称:IRcvStr * * 功能描述:从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件 * 地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。 * 如果返回1表示操作成功,否则操作有误。 * * * 参 数:sla - 从器件地址 * suba - 从器件子地址 * *s - 数据 * no - 数据字节数目 * * 返 回 值:0 -- 失败 * 1 -- 成功 * * 注 意:使用前必须已结束总线。 *****************************************************************************/ uint8 IRcvStr(uint8 sla,uint8 suba,uint8 *s,uint8 no) { Start_I2c(); /*启动总线*/ SendByte(sla); /*发送器件地址*/ if(ack==0)return(0); SendByte(suba); /*发送器件子地址*/ // if(ack==0)return(0); // SendByte(sla+1); if(ack==0)return(0); while(no > 0) { *s++ = RcvByte(); if(no > 1) Ack_I2c(0); /*发送就答位*/ else Ack_I2c(1); /*发送非应位*/ no--; } Stop_I2c(); /*结束总线*/ return(1); } /****************************************************************************** * 函数名称:ctrPCA9554LED * * 功能描述:通过IIC总线控制PCA9554的输出,进而控制相应的LED。 * * * 参 数:LED - 所控制的LED * operation - 开或关操作 * * 返 回 值:无 * * * 注 意:PCA9554的地址为:0x40 *****************************************************************************/ void ctrPCA9554LED(uint8 led,uint8 operation) { uint8 output = 0x00; uint8 *data = 0; if(ISendStr(0x40,0x03,&output,1)) //配置PCA9554寄存器 { switch(led) { case 0: //LED0控制 if (operation) { output = PCA9554ledstate & 0xfe; } else { output = PCA9554ledstate | 0x01; } break; case 1: //LED1控制 if (operation) { output = PCA9554ledstate & 0xfd; } else { output = PCA9554ledstate | 0x02; } break; case 2: //LED2控制 if (operation) { output = PCA9554ledstate & 0xf7; } else { output = PCA9554ledstate | 0x08; } break; case 3: //LED3控制 if (operation) { output = PCA9554ledstate & 0xfb; } else { output = PCA9554ledstate | 0x04; } break; case 4: //LED4控制 if (operation) { output = PCA9554ledstate & 0xdf; } else { output = PCA9554ledstate | 0x20; } break; case 5: //LED5控制 if (operation) { output = PCA9554ledstate & 0xef; } else { output = PCA9554ledstate | 0x10; } break; default:break; } if(ISendStr(0x40,0x01,&output,1)) //写PCA9554输出寄存器 { if(IRcvByte(0x40,data)) //读PCA9554输出寄存器 { PCA9554ledstate = *data; } } } } /****************************************************************************** * 函数名称:PCA9554ledInit * * 功能描述:初始化6个LED,即关闭所有的LED * * 参 数:无 * * 返 回 值:无 * *****************************************************************************/ void PCA9554ledInit() { uint8 output = 0x00; uint8 *data = 0; if(ISendStr(0x40,0x03,&output,1)) //配置PCA9554寄存器 { output = 0xbf; if(ISendStr(0x40,0x01,&output,1)) //写输出寄存器 { if(IRcvByte(0x40,data)) //读输出寄存器 { PCA9554ledstate = *data; } } } }
相关文章推荐
- 座位争执--Vijos P1245 (校内Vijos P1361)
- web.xml文件出错导致了There is no Action mapped for namespace / and action name
- JQUERY中的事件处理:RETURN FALSE、阻止默认行为、阻止冒泡以及兼容性问题
- Delphi7 Just In Time debugger 与VS冲突
- 【转】Objective-C Class Dump
- CWinAppEx::SetRegistryBase 设置应用程序的默认注册表路径。
- CoreAnimation编程指南(七)图层Action
- Eclipse的秘籍
- jsp开发中不支持EL问题
- 路由修改 route
- CoreAnimation编程指南(六)动画
- 解决linux下erlang关闭port同时也关掉与其连接的c语言进程
- 音箱等非电脑设备不能自动读取U盘文件的解决办法
- win7下不能安装net farmework 4.5解决方法总结
- poj 2689 Prime Distance 素数
- 不支持多拨的无线路由 一号多拨+无线
- 017、SearchManager的使用
- 如何快速屏蔽触摸
- 2014腾讯校园招聘笔试题
- 很酷的结合----芒果和machine learning的故事