精华内容
下载资源
问答
  • 51单片机C语言延时函数怎么定义和使用

    万次阅读 多人点赞 2019-01-06 17:38:04
    C语言定义延时函数主要通过无意义指令的执行来达到延时的目的。C程序中可使用不同类型的变量来进行延时设计。经实验测试,使用unsigned char类型具有比unsigned int更优化的代码,在使用时应该使用unsigned char作为...

    C语言定义延时函数主要通过无意义指令的执行来达到延时的目的。C程序中可使用不同类型的变量来进行延时设计。经实验测试,使用unsigned char类型具有比unsigned int更优化的代码,在使用时应该使用unsigned char作为延时变量。
      以某晶振为12MHz的单片机为例,晶振为12MHz即一个机器周期为1us。现在定义一个延时xms毫秒的延时函数。

     void delay(unsigned int xms) // xms代表需要延时的毫秒
          {
          unsigned int x,y;
          for(x=xms;x>=0;x--)
          for(y=110;y>=0;y--);
          }
    

    1.51单片机C语言延时函数的使用
    下面给出一些经典的延时函数,(1)500ms延时子程序如下:

    void delay500ms(void)
    {
      unsigned char i,j,k;
      for(i=15;i>=0;i--)
      for(j=202;j>=0;j--)
      for(k=81;k>=0;k--);
    }
    

    计算分析:程序共有三层循环,一层循环n:R52 = 812 = 162us DJNZ 2us;二层循环m:R6*(n+3) = 202165 = 33330us DJNZ 2us + R5赋值 1us = 3us;三层循环: R7(m+3) = 1533333 = 499995us DJNZ 2us + R6赋值 1us = 3us
    循环外: 5us 子程序调用 2us + 子程序返回 2us + R7赋值 1us = 5us
    延时总时间 = 三层循环 + 循环外 = 499995+5 = 500000us =500ms
    计算公式:延时时间=[(2
    R5+3)*R6+3]*R7+5
    (2)200ms延时子程序:

    void delay200ms(void)
    {
      unsigned char i,j,k;
      for(i=5;i》0;i--)
      for(j=132;j》0;j--)
      for(k=150;k》0;k--);
    }
    

    (3)10ms延时子程序:

    void delay10ms(void)
    {
      unsigned char i,j,k;
      for(i=5;i》0;i--)
      for(j=4;j》0;j--)
      for(k=248;k》0;k--);
    }
    

    (4)1s延时子程序:

    void delay1s(void)
    {
      unsigned char h,i,j,k;
      for(h=5;h》0;h--)
      for(i=4;i》0;i--)
      for(j=116;j》0;j--)
      for(k=214;k》0;k--);
    }
    

    关于单片机C语言的精确延时,网上很多都是大约给出延时值没有准确那值是多少,也就没有达到精确高的要求,而本函数克服了以上缺点,能够精确计数出要延时值且精确达到1us,本举例所用CPU为STC12C5412系列12倍速的单片机,只要修改一下参数值其它系例单片机也通用,适用范围宽。
    共有三条延时函数说明如下:
      函数调用分两级:一级是小于10US的延时,二级是大于10US的延时

    //小于10US的【用1US级延时】

    //----------微秒级延时---------

    for(i=X;i》X;i–) 延时时间=(3+5*X)/12 提示(单位us, X不能大于255)

    //======大于10US《小于21.9955Ms的可用【10US级延时函数】=

    void Delay10us(uchar Ms)
    {
      uchar data i;
      for(;Ms》0;Ms--)
      for(i=26;i》0;i--);
    }
    

    i=[(延时值-1.75)*12/Ms-15]/4
      如想延时60US则 i=[(60-1.75)*12/6-15]/4=25.375≈26; 修改i的值=26,再调用上面的【10US级延时函数】Delay10us(6); 则就精确延时60US;如果想延时64US可以用这二种函数组合来用: Delay10us(6); for(i=9;i》X;i–) 共延时64US
      关于单片机C语言的精确延时,网上很多都是大约给出延时值没有准确那值是多少,也就没有达到精确高的要求,而本函数克服了以上缺点,能够精确计数出要延时值且精确达到1us,本举例所用CPU为STC12C5412系列12倍速的单片机,只要修改一下参数值其它系例单片机也通用,适用范围宽。

    共有三条延时函数说明如下:

    函数调用分两级:一级是小于10US的延时,二级是大于10US的延时

    //小于10US的【用1US级延时】

    //----------微秒级延时---------

    for(i=X;i》X;i–) 延时时间=(3+5*X)/12 提示(单位us, X不能大于255)

    //======大于10US《小于21.9955Ms的可用【10US级延时函数】=

    void Delay10us(uchar Ms)
    {
      uchar data i;
      for(;Ms》0;Ms--)
      for(i=26;i》0;i--);
    }
    

    i=[(延时值-1.75)*12/Ms-15]/4
      如想延时60US则 i=[(60-1.75)*12/6-15]/4=25.375≈26; 修改i的值=26,再调用上面的【10US级延时函数】Delay10us(6); 则就精确延时60US;
      如果想延时64US可以用这二种函数组合来用: Delay10us(6); for(i=9;i》X;i–) 共延时64US
    2.下面给出有关在C51中延时子程序设计时要注意的问题(一些经验之谈)

    (1)、在C51中进行精确的延时子程序设计时,尽量不要或少在延时子程序中定义局部变量,所有的延时子程序中变量通过有参函数传递。
     (2)、在延时子程序设计时,采用do…while,结构做循环体要比for结构做循环体好。
     (3)、在延时子程序设计时,要进行循环体嵌套时,采用先内循环,再减减比先减减,再内循环要好。

    一. 500ms延时子程序产生的汇编:

    C:0x0800 7F0F MOV R7,#0x0F
    
      C:0x0802 7ECA MOV R6,#0xCA
    
      C:0x0804 7D51 MOV R5,#0x51
    
      C:0x0806 DDFE DJNZ R5,C:0806
    
      C:0x0808 DEFA DJNZ R6,C:0804
    
      C:0x080A DFF6 DJNZ R7,C:0802
    
      C:0x080C 22 RET
    

    二.200ms延时子程序产生的汇编

    C:0x0800 7F05 MOV R7,#0x05
    
      C:0x0802 7E84 MOV R6,#0x84
    
      C:0x0804 7D96 MOV R5,#0x96
    
      C:0x0806 DDFE DJNZ R5,C:0806
    
      C:0x0808 DEFA DJNZ R6,C:0804
    
      C:0x080A DFF6 DJNZ R7,C:0802
    
      C:0x080C 22 RET
    

    三.10ms延时子程序产生的汇编:

    C:0x0800 7F05 MOV R7,#0x05
    
      C:0x0802 7E04 MOV R6,#0x04
    
      C:0x0804 7DF8 MOV R5,#0xF8
    
      C:0x0806 DDFE DJNZ R5,C:0806
    
      C:0x0808 DEFA DJNZ R6,C:0804
    
      C:0x080A DFF6 DJNZ R7,C:0802
    
      C:0x080C 22 RET
    

    四.1s延时子程序产生的汇编

    C:0x0800 7F05 MOV R7,#0x05
    
      C:0x0802 7E04 MOV R6,#0x04
    
      C:0x0804 7D74 MOV R5,#0x74
    
      C:0x0806 7CD6 MOV R4,#0xD6
    
      C:0x0808 DCFE DJNZ R4,C:0808
    
      C:0x080A DDFA DJNZ R5,C:0806
    
      C:0x080C DEF6 DJNZ R6,C:0804
    
      C:0x080E DFF2 DJNZ R7,C:0802
    
      C:0x0810 22 RET
    

    3.另外一些关于延时的例子
    http://www.ceet.hbnu.edu.cn/bbs/viewthread.php?TId=3749,作者:小秋

    晶振:12MHz

    1:5~500us

    void delay(unsigned char i)
    {
      while(--i) ;
    }
    

    计算方法:ix2+5 可完成5~515us的延时

    2:10us~2ms

    void delay(unsigned char i)
    {
      for( ;i》0 ;i--) ;
    }
    

    计算方法:ix8+10 可完成10us~2.050ms的延时

    3:2ms~130ms

    void delay(unsigned char i,unsigned char j)
    {
      for( ;j》0 ;j--)
      for( ;i》0 ;i--) ;
    }
    

    计算方法:(ix2+3)xj+5 u


    转载自:http://www.elecfans.com/emb/580729_a.html

    展开全文
  • 利用单片机延时函数空耗时间,延时1s来实现,等学完单片机定时器中断,就可以设计精确计时程序。1.程序设计#include//头文件#defi ne uchar unsigned char //宏定义#defi ne uint unsigned intuchar code table []=...

    如何实现每秒间隔显示数字呢?利用单片机延时函数空耗时间,延时1s来实现,等学完单片机定时器中断,就可以设计精确计时程序。

    66d75b93b4411f96cc5da4ca29d5e663.png

    1.程序设计

    #include//头文件

    #defi ne uchar unsigned char //宏定义

    #defi ne uint unsigned int

    uchar code table []={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//共阴数码管编码

    void delay(uint a)//延时函数

    {

    uint j,i;

    for(j=a;j>0;j--)

    for(i=110;i>0;i--);

    }

    void main()//主函数

    {

    uint num;//定义变量

    while(1)

    {

    delay(1000); //延时时间大约1s

    P1=0xfe;

    P0=table[num];

    num++;

    if(num>9)

    num=0;

    }

    }

    2.程序解释

    ①num++;即num=num+1。

    ②P1=0xfe;选通第一个数码管。

    ③if(num>9)

    num=0;

    以上是简写,写全如下:

    if(num>9)

    {

    num=0;

    }

    如果num变量数字大于9,num重新赋值为“0”。

    3.面包板制作展示

    ce99362b64ed0bd53c1d57b819b3a6fc.png

    “显示数字”面包板制作展示

    4.C语言基础知识

    (1)if语句

    格式一:

    if(表达式){语句1;语句2;}

    步骤:如果表达式为“真”,则执行语句1和语句2,如果为“假”,则跳过语句1与语句2,执行其他的程序。

    格式二:

    if(表达式){语句1;语句2;}

    else{语句3;语句4;}

    步骤:如果表达式为“真”,则执行语句1和语句2,如果为“假”,则执行语句3与语句4。

    (2)运算符

    常见运算符如表

    cadef975f5c5291ddba431c64f7fbfe7.png

    运算符

    上面的程序只是让“num”自加到9,如何显示大于“9”的数字呢?

    当显示大于9的数值就需要用到数字的分解。

    3)数字分解

    以两位数字为例,一位数码管是无法显示两个数字,数字分解是必需的,分解后分别送到两个数码管显示。比如一个两位数字是num,分解十位(a表示),a=num/10(称之为求模);分解个位(b表示),b=num%10(称之为求余)。

    展开全文
  • 函数调用关系:(延时任务的clock减少的函数调用) usrClock-->tickAnnounce-->windTickAnnounce-->Q_ADVANCEN 先说一下等待任务的时间片减少。 系统中有一个全局队列定义如下,就是专门存放等待任务的。 Q_HEAD ...

    函数调用关系:(延时任务的clock减少的函数调用)

    usrClock-->tickAnnounce-->windTickAnnounce-->Q_ADVANCEN

    先说一下等待任务的时间片减少。
    系统中有一个全局队列定义如下,就是专门存放等待任务的。
    Q_HEAD	  tickQHead;
    tickQHead队列的结构体定义:
    typedef struct		
        {
        Q_NODE  *pFirstNode;	/*第一个任务的节点*/
        UINT     qPriv1;		/**/
        UINT     qPriv2;		/**/
        Q_CLASS *pQClass;		/*每一类都对应一个操作函数集*/
        } Q_HEAD;
    

    每个类对应的操作函数集:
    typedef struct q_class		/* Q_CLASS */
        {
        FUNCPTR createRtn;		/* create and initialize a queue */
        FUNCPTR initRtn;		/* initialize a queue */
        FUNCPTR deleteRtn;		/* delete and terminate a queue */
        FUNCPTR terminateRtn;	/* terminate a queue */
        FUNCPTR putRtn;		/* insert a node into q with insertion key */
        FUNCPTR getRtn;		/* return and remove lead node routine */
        FUNCPTR removeRtn;		/* remove routine */
        FUNCPTR resortRtn;		/* resort node to new priority */
        FUNCPTR advanceRtn;		/* advance queue by one tick routine */
        FUNCPTR getExpiredRtn;	/* return and remove an expired Q_NODE */
        FUNCPTR keyRtn;		/* return insertion key of node */
        FUNCPTR calibrateRtn;	/* calibrate every node in queue by an offset */
        FUNCPTR infoRtn;		/* return array of nodes in queue */
        FUNCPTR eachRtn;		/* call a user routine for each node in queue */
        FUNCPTR restoreRtn;         /* restore a node position in queue */
        FUNCPTR nextRtn;		/* return next node in a queue */
        struct q_class *valid;	/* valid == pointer to queue class */
        } Q_CLASS;
    
    这是系统时钟的中断函数,在这个函数里面对时间片进行了减少操作。

    void windTickAnnounce (void)
    {
    	....
           Q_ADVANCEN (&tickQHead, 1);
    	....
    }
    

    减少队列上任务的时间片具体操作操作:

    #define Q_ADVANCEN(pQHead, n)						\
        if (((Q_HEAD *)pQHead)->pQClass->valid == qPriDeltaClassId &&	\
    	((Q_HEAD *)pQHead)->pFirstNode != NULL)				\
    	{								\
    	if (n > ((Q_PRI_NODE *)((Q_HEAD *)pQHead)->pFirstNode)->key)	\
    	    ((Q_PRI_NODE *)((Q_HEAD *)pQHead)->pFirstNode)->key = 0;	\
    	else								\
    	    ((Q_PRI_NODE *)((Q_HEAD *)pQHead)->pFirstNode)->key -= n;	\
    	}
    
    typedef struct		
        {
        DL_NODE	node;	/*组成队列的节点*/
        ULONG	key;	/*任务的延迟时间*/
        } Q_PRI_NODE;
    
    分开说明:

    (((Q_HEAD *)pQHead)->pQClass->valid == qPriDeltaClassId &&	\
    	((Q_HEAD *)pQHead)->pFirstNode != NULL)
    这句话,首先判定tickQHead的操作函数集是否是qPriDeltaClassId,然后在判断第一个节点是否为空,如果都成立,接着往下执行。

    if (n > ((Q_PRI_NODE *)((Q_HEAD *)pQHead)->pFirstNode)->key)	\
    	    ((Q_PRI_NODE *)((Q_HEAD *)pQHead)->pFirstNode)->key = 0;	\
    
    当1大于第一个节点的key(延时时间)时,就赋值为0,否则减去1.


    这里就出现一个问题,每次操作时间片时,系统竟然只是操作第一个节点的时间片值,后面任务的时间片没有动,这是怎么回事呢?
    问题方后面解释,先来看看把任务放到等待队列时的操作:

    把任务放入到队列的操作函数:
    void qPriDeltaPut
        (
        Q_PRI_HEAD  *pQPriHead,  /*要放入的等待队列*/ 
        Q_PRI_NODE  *pQPriNode,  /*要操作的任务节点*/ 
        ULONG       key	     /*延时时间*/ 
        )
        {
        /*得到队列的第一个节点*/
        FAST Q_PRI_NODE *pQNode = (Q_PRI_NODE *) DLL_FIRST (pQPriHead);
    
        pQPriNode->key = key;		/*为要操作的任务赋值等待时间*/
    
    /*判断是否是空队列,如果是空队列就把任务放入到最后。*/
        while (pQNode != NULL)		
            {
    /*如果要插入任务的延时值小于pQNode的时间,就插入到pQNode前面,并把pQNode的时间减少要插入任务的延时时间;如果延时时间大于pQNode的时间,就把pQPriNode的延时时间减去pQNode的时间并h插入到pQNode的后面*/
    	if (pQPriNode->key < pQNode->key)
    	    {
    	    dllInsert (pQPriHead, DLL_PREVIOUS (&pQNode->node),
    		       &pQPriNode->node);
    
    	    /* Now decrement the delta key of the guy behind us. */
    
    	    pQNode->key -= pQPriNode->key;
    	    return;				/* we're done */
    	    }
    
    	pQPriNode->key -= pQNode->key;
    	pQNode = (Q_PRI_NODE *) DLL_NEXT (&pQNode->node);
    	}
    
        dllInsert (pQPriHead, (DL_NODE *) DLL_LAST (pQPriHead), &pQPriNode->node);
        }
    



    咱们列举一个例子来解答这个问题:
    有三个任务,都延时自己后面执行,A延时15秒,B延时16秒,C延时17秒,看清楚了,这三个任务插入到队列中就成了这样:
    第一个:A延时15秒
    第二个:B延时1秒,
    第三个:C延时2秒,

    这个时候B,D的值分别是和A的差值,随后时钟运行,减少延迟时间时,每次只减少第一个,后面不动,当A到时间时,B就变为了第一个,这个B已经延时15秒了,加上准备延时的时间1秒,正好是设定的延时16秒,同理C任务也是这样的。
    这样有什么好处呢?
    不管有多少任务,只需要操作第一个,真的是大大的方便了不少啊。










    展开全文
  • //定义一个变量,用来给P1口赋值 void main() { aa=0xfe; //1111 1110 while (1) { P1=aa; //点亮第一个发光二极管 delayms(500); //延时500ms aa=_crol_(aa,1); //将AAA循环左移一位后...
  •  //定义一个变量,用来给P1口赋值 void main() {<!-- -->  aa=0xfe; //1111 1110  while (1)  {<!-- -->  P1=aa; //点亮第一个发光二极管  delay...
  • ZigBee流水灯怎么实现

    2014-12-18 10:10:39
    * 入口参数: msec 延时参数,值越大,延时越久 * 出口参数: 无 ****************************************************************************/ void DelayMS(uint msec) { uint i,j; for (i=0; i; i++) for...
  • 请问问题出在哪里,怎么解决 原来正常的情况:单片机和APP连接后,APP能控制LED1、2的亮灭,并显示LED等的状态 #include "DHT11.h" #include #include "string.h" extern unsigned char F16...
  • 由于64M主频,15.6K的PWM,占空比精度1.2%的话,也就是需要50个时钟周期就需要进行一次中断,并且执行完中断函数中的各类判断的语句。处理速度跟不上,用不成。 2.用定时器中断进行电平翻转,同时改变定时器中断...
  • # 函数定义 def PC_poweroff(self): global delayTime val = int(tk.Entry.get(delayTime)) i=0 while i i= i+1 time.sleep(0.5) # print(i) valN = str(i) powerofflabel = tk.Label(PC_UI,...
  • 延时函数 **********************************************************************/ void DelayMs(uint i) //0.25ms {uchar j; for(;i!=0;i--) {for(j=250;j!=0;j--) {;}} } /********...
  • 函数名称:DS18B20_Reset 功 能:对DS18B20进行复位初始化操作 参 数:无 返回值 :初始化状态标志:0--失败,1--成功 ********************************************/ uchar DS18B20_Reset(void) { uchar ...
  • STM32F103下模拟I2C的接口代码

    万次阅读 2017-03-17 17:23:22
    硬件I2C虽然高效, 但是调试的时候老是遇到...废话少说, 这就送上完全注释版的模拟I2C代码, STM32系列下适用, 其他单片机就要修改SCL和SDA的定义以及修改延时函数. #include "stm32f10x.h" #define HIGH 1 #define LOW

    硬件I2C虽然高效, 但是调试的时候老是遇到这样那样的问题, 赶项目也没有太多时间在里面折腾, 就使用了模拟I2C来完成. 效率虽然不怎么样, 胜在简单快捷...

    废话少说, 这就送上完全注释版的模拟I2C代码, STM32系列下适用, 其他单片机就要修改SCL和SDA的定义以及修改延时函数.

    #include "stm32f10x.h"
    
    #define HIGH 1
    #define LOW 0
    
    #define TRUE 1
    #define FALSE
    
    /* 这里使用的是STM32F103RC的片子, 使用PB6, PB7分别作为SCL和SDA, 
    其他片子根据需求选用合适的GPIO口 */
    #define SDA_IN()  {GPIOB->CRL& = 0X0FFFFFFF; GPIOB->CRL |= 4<<28;}
    #define SDA_OUT() {GPIOB->CRL& = 0X0FFFFFFF; GPIOB->CRL |= 3<<28;}
    #define IIC_SCL    PBout(6) //SCL
    #define IIC_SDA    PBout(7) //SDA	 
    #define READ_SDA   PBin(7)  //输入SDA
    
    void delay_us(u16 time)
    {    
       u16 i = 0;  
       while(time--)
       {
          i = 10;   //随便定义的一个值, 无意义, 纯粹是消耗CPU时间而已, 可能会编译器被优化  
          while(i--);    
       }
    }
    
    /* 初始化I2C */
    void IIC_Init(void)
    {
    	GPIO_InitTypeDef GPIO_Init_Structure;
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    	GPIO_Init_Structure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    	GPIO_Init_Structure.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_Init_Structure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB,&GPIO_Init_Structure);
    	GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);
    }
    
    /* 产生I2C的起始信号 */
    void IIC_Start(void)
    {
        /* 设置SDA线为输出 */
    	SDA_OUT();     
        
        /* 在开始传输数据之前, 先让SDA和SCL都拉高 */
    	IIC_SDA = HIGH;	  	  
    	IIC_SCL = HIGH;
        
    	delay_us(5);
        
        /* 根据I2C总线定义: SCL为高时, 数据由高跳变至低表示开始信号 */
     	IIC_SDA = LOW;
    	delay_us(5);
        
        /* 
        SCL在低的时候, 是不传送任何数据, 也不作为开始和结束的条件, 
        所以这样我们可以开始数据的发送而不会导致产生开始或者结束信号 
        这个就是所谓的钳住I2C总线
        */
    	IIC_SCL = LOW;
    }
    
    /* 产生I2C停止信号 */
    void IIC_Stop(void)
    {
    	SDA_OUT();//sda线输出
        
        /* 
        先让SCL拉低这样才能将SDA切换至低的状态而不导致重复产生开始信号 
        还记得前面对I2C Start的注释吗?就是SCL为高的时候, SDA由高变低
        */
    	IIC_SCL = LOW;
        
        /* 
            前面已经将SCL拉低了, 所以这里我们就可以肆无忌惮的将SDA拉低, 
            为产生结束信号做好准备
        */
    	IIC_SDA = LOW;
        
     	delay_us(5);
        
        /* Okay, 我们开始产生结束信号: 首先需要将SCL拉高(为什么要拉高? 因为I2C总线规定了
        只有在SCL为高的时候才是传输数据或者产生开始/结束信号的有效时间) */
    	IIC_SCL = HIGH; 
        
        /* 好了, 前面已经提前将SDA拉低了, 所以这里我们只要简单的将SDA置为高就完成了 */
    	IIC_SDA = HIGH;
    	delay_us(5);							   	
    }
    
    /*
    应答信号的意义:
    Master每发送完8bit数据后需要等待Slave的ACK
    也就是在第9个Clock, 如果从(Slave)IC发出ACK, 那么SDA会被拉低
    如果没有ACK, SDA会被置高,这样会导致Master发出Restart或者Stop流程
    */
    /* 
        等待应答信号到来
    */
    u8 IIC_Wait_Ack(void)
    {
    	u8 ucErrTime = 0; 
    	IIC_SDA = HIGH;
        delay_us(5);
        
        /* 设置SDA为输入模式, 以便读取SDA上的ACK */
    	SDA_IN();      
        
        /* 置SCL为高, 进行读取操作 */
    	IIC_SCL = HIGH;
        delay_us(5); 	
        
    	while(READ_SDA)
    	{
    		ucErrTime++;
    		if(ucErrTime > 250)
    		{//指定时间内没有收到从IC的ACK, 进行超时处理
    			return FALSE;
    		}
    	}
        
        /* 
        好了, 这里表示没有超时并且读取到了SDA为低, 表示收到ACK确认了 
        那么就可以收工回家, 设置一下SCL为低电平(为啥? 因为有效操作都是在
        SCL为高的时候才进行的)
        */
    	IIC_SCL = LOW;
        
    	return TRUE;  
    }
    
    /*
     发出ACK确认的操作
     发出这个操作的意义在于让从IC知道我们已经收到数据了
     这样, 从IC就不会进行Restart或者Stop流程
    */
    void IIC_Ack(void)
    {
        /* 第一步先让SCL拉低先, 避免SDA变化影响I2C */
    	IIC_SCL = LOW;
        
        /* 然后我们设置一下SDA为输出模式, 准备输出数据 */
    	SDA_OUT();
        
        /* SDA拉低, 这样就将确认信号放到总线上, 就差时钟信号了 */
    	IIC_SDA = LOW;
        
    	delay_us(5);
        
        /* SCL拉高, 产生必备的有效操作时钟信号 */
    	IIC_SCL = HIGH;
        
    	delay_us(5);
        
        /* 
        前面延时了一会了, 时钟差不多了, 那么就结束ACK信号
        总不能一直占着总线不放吧 */
    	IIC_SCL = LOW;
    }
    
    /*
    对于NACK, I2C总线是这样定义的:
    当在第9个时钟脉冲的时候SDA线保持高电平, 就被定义为NACK.
    Master要么产生Stop条件来放弃此次传输,要么重复Start条件来
    发起一个新的开始
    */
    void IIC_NAck(void)
    {
    	IIC_SCL = LOW;
    	SDA_OUT();
        
        /* 根据定义, 拉高SDA, 作为NACK的定义 */
    	IIC_SDA = HIGH;
    	delay_us(5);
        
        /* 置为高电平, 发送NACK信号出去 */
    	IIC_SCL = HIGH;
    	delay_us(5);
        
        /* SCL拉低, 发送完毕 */
    	IIC_SCL = LOW;
    }
    
    void IIC_Send_Byte(u8 txd)
    {                        
        u8 t;  
        /* 既然开始了数据的发送, 那么先将SDA口切换为输出模式先 */    
    	SDA_OUT(); 	 
    
        /* 时钟信号拉低, 将数据准备好再拉高进行传输 */    
        IIC_SCL = LOW;
        for(t = 0; t < 8; t++)
        {     
            /* I2C数据是按照大端传输的, 也就是高位先传输 */
    		if((txd&0x80) >> 7)
    			IIC_SDA = HIGH;
    		else
    			IIC_SDA = LOW;
            
    		txd <<= 1; 
            /* 做一下延时是有必要的 */        
    		delay_us(5);   
            
            /* SCL拉高传送数据 */
    		IIC_SCL = HIGH;
            
    		delay_us(5);
            
            /* 拉低SCL, 传输完毕 */
    		IIC_SCL = LOW;	
            
    		delay_us(5);
        }	 
    } 
    
    u8 IIC_Read_Byte(void)
    {
    	unsigned char i, receive = 0;
        
        /* 切换SDA口为输入模式, 准备读取数据 */
    	SDA_IN();
        
        for(i = 0; i < 8; i++ )
    	{
            /* SCL拉低 */
            IIC_SCL = LOW; 
            delay_us(5);
            
            /* 再拉高SCL, 产生一个有效的时钟信号 */
    		IIC_SCL = HIGH;
            
            /* 读取总线上的数据 */
            receive = (receive << 1) | READ_SDA;
            
    		delay_us(5); 
        }
        
    	return receive;
    }
    


    展开全文
  • 单片机 keil流水灯实验

    千次阅读 2010-02-08 02:11:00
    做流水灯实验以前,必须先弄清楚各个发光二极管是怎么控制的,其次,在了解了keil的内部左移右移函数,就可以写...此外还要写一个延时函数,可以是带参数的,也可以不带。在while大循环里,不能忘了点亮一盏灯,就要把
  • 1:清屏printf(“\033c”); 2:延时sleep(1);延时1s 3:getchar()一方面,实现...1)单独写一个.h文件把要用到的#include全部包含进去,结构体定义也写这里,宏替换也写这里,函数申明也写这里 2)函数部分一个函
  • stm32的.c文件的东西全都写在了.h里面,为什么还能不编译出错,下载在板子里也是对的,自己尝试过分成.c和.h文件,但是会报很多的错,怎么能分离出来呢? 部分代码如下: ``` static u8 fac_us=0;//us延时倍乘数 ...
  • 5.4 NULL是什么,它是怎么定义的? 5.5 在使用非零位模式作为空指针的内部表示的机器上,NULL是如何定义的? 5.6 如果NULL定义成#defineNULL((char*)0),不就可以向函数传入不加转换的NULL了吗? 5.7 我的编译器...
  • 5.4 NULL是什么,它是怎么定义的? 56 5.5 在使用非零位模式作为空指针的内部表示的机器上,NULL 是如何定义的? 56 5.6 如果NULL定义成#define NULL((char *)0) ,不就可以向函数传入不加转换的NULL 了吗? ...
  • C语言编程要点

    2017-09-18 00:10:37
    9.4. 在把数组作为参数传递给函数时,可以通过sizeof运算符告诉函数数组的大小吗? 140 9.5. 通过指针或带下标的数组名都可以访问数组中的元素,哪一种方式更好呢? 141 9.6. 可以把另外一个地址赋给一个数组名吗? 143...
  • 《你必须知道的495个C语言问题》

    热门讨论 2010-03-20 16:41:18
    5.4 NULL是什么,它是怎么定义的? 56 5.5 在使用非零位模式作为空指针的内部表示的机器上,NULL 是如何定义的? 56 5.6 如果NULL定义成#define NULL((char *)0) ,不就可以向函数传入不加转换的NULL 了吗? ...
  • o 6.4 NULL 是什么, 它是怎么定义的? o 6.5 在使用非全零作为空指针内部表达的机器上, NULL 是如何定义的? o 6.6 如果 NULL 定义成 #define NULL ((char *)0) 难道不就可以向函数传入不加转换的 NULL 了吗? o...
  • 在write后面加个延时函数 sleep 之后可以完整读到数据 但我老师说串口这种即时通讯怎么能延时 不合逻辑 代码如下: 主函数 main .cpp #include <stdio.h> /*标准输入输出定义*/ #include <stdlib.h> /*标准...
  • ES6 实现自己的 Promise

    2020-12-26 19:05:55
    不用着急后面会说到怎么添加处理函数)。当reject函数调用后,promise状态转化为rejected,并且执行失败返回的处理函数。 现在我们的代码大概是这样的: <pre><code> javascript class ...
  • 以下是camer_def.h的内容: #ifndef __CAMERDEF_H__ #define __CAMERDEF_H__ ...该函数已封装在 tcm_dll.dll 中了,但以上是VC的代码,看不懂,也不知道怎么转换,请高手帮忙转成 vb.net 的代码,谢谢了!!
  • 你必须知道的495个C语言问题(PDF)

    热门讨论 2009-09-15 10:25:47
    5.4 NULL 是什么, 它是怎么定义的? . . . . . . . . . . . . . . . . . . 23 5.5 在使用非全零作为空指针内部表达的机器上, NULL 是如何定义 的? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ...
  • 实物LCD1602显示温度为0,其他信息正常显示,仿真一切正常,若将显示温度的函数单独提取成文件,则正常显示温度,不知道怎么改 PS只需看主函数,LCD1602.h和temp.h就行 ``` #include"key.h" #include"lcd1602.h...
  • -GetConfirmFormModifiedHideReference的函数中的ConfirmFormModified简化为Confirm,所以此函数更名为GetConfirmHideReference。 -增加两个属性EnableConfirmOnClose(默认false),CloseAction(Hide, ...
  • Android 上百实例源码分析以及开源分析 集合打包4

    千次下载 热门讨论 2012-07-10 21:54:03
    在Jamendo中,主要是通过再定义一个SeparatedListAdapter来进行这个工作,我们来看看它是怎么实现的:我理解的Adapter过程,首先通过调用getCount()来获得总Row数目,然后对一行调用getView进行绘制,因此要实现在...
  • 精通Oracle PL/SQL--详细书签版

    热门讨论 2012-08-21 13:06:28
     对于oracle技术人员而言,怎么强调掌握pl/sql的重要性都不过分。但是,真正精通pl/sql绝非易事。事实上,在现有的oracle应用程序中充斥着太多质量不佳的pl/sql代码,它们要么没有充分利用oracle特有的功能,要么是...

空空如也

空空如也

1 2
收藏数 34
精华内容 13
关键字:

怎么定义延时函数