• STC8H_硬件IIC


    原理图部分

    使用STC8H单片机
    在这里插入图片描述

    IIC通讯时序原理就不再赘述了

    STC公司从标准IIC协议中更改了两种机制如下:
    ◆发送起始信号(START)后不进行仲裁
    ◆时钟信号(SCL)停留在低电平时不进行超时检测

    I2C相关的寄存器

    在这里插入图片描述

    I2C配置寄存器(I2CCFG),总线速度控制

    在这里插入图片描述

    只有当IIC模块工作在主机模式时,MSSPEED参数设置的等待参数才有效。此等待参数主要用于主机模式的以下几个信号:

    在这里插入图片描述
    例1:当MSSPEED=10时,TSSTA=THSTA=TSSTO=THSTO=THCK=24/FOSC
    例2:当24MHz的工作频率下需要400K的I2C总线速度时,MSSPEED=(24M/400K /2-4)/2=13

    I2C从机状态寄存器(I2CSLST)

    在这里插入图片描述

    在这里插入图片描述
    上图标记的寄存器实例中运用得到

    I2C从机地址寄存器(I2CSLADR)

    在这里插入图片描述

    I2C数据寄存器(I2CTXD,I2CRXD)

    在这里插入图片描述

    代码部分

    对IIC引脚初始化,我这里选择了P3.3和P3.2引脚分别是IICSDA以及IICSCL。

    #define  HARDIIC_SDA_IN      {P3M1&=~0x08;P3M0&=~0x08;}    //P33双向IO口   
    #define  HARDIIC_SCL_IN      {P3M1|=0x04;P3M0&=~0x04;}     //高阻输入
    
    • 1
    • 2

    IIC从机初始化

    void IIC_init()
    {
    	EA = 1; // 控制总中断
    	//IIC初始化--------------
    	HARDIIC_SCL_IN; //P32双向IO口  
    	HARDIIC_SDA_IN; //P33双向IO口 
    
    	P_SW2 = ((P_SW2 & (~(1<<7))) | (1<<7));    //开启 扩展 RAM 区特殊功能寄存器(XFR)访问控制寄存器
    	P_SW2 = ((P_SW2 & (~(3<<4))) | (3<<4));		 //外设端口切换控制寄存器
    
    	I2CCFG = 0x81; //使能 I2C 从机模式
    	I2CSLADR = 0xFF; //这里接收所有的设备地址
    	//下面是对设备地址必须相同的解释
    	//设置从机设备地址寄存器 I2CSLADR=0101_1010B  最后一位设置为1 接受所有的设备地址
    	//即 I2CSLADR[7:1]=010_1101B,MA=0B。
    	//由于 MA 为 0,主机发送的的设备地址必须与
    	//I2CSLADR[7:1]相同才能访问此 I2C 从机设备。
    	//主机若需要写数据则要发送 5AH(0101_1010B)
    	//主机若需要读数据则要发送 5BH(0101_1011B)
    	
    	I2CSLST = 0x00; //IIC从机状态寄存器清零
    	I2CSLCR = 0x78; //使能从机模式中断
    
    	isda = 1; //用户变量初始化
    	isma = 1;//寄存器地址
    	addr = 0;//设备地址
    	I2CTXD = buffer[addr];
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    IIC中断服务函数

    //调压芯片或IIC逻辑 开始信号 -> 设备地址 -> 从机应答 -> 储存地址 -> 从机应答 -> 数据1 -> 从机应答 -> 数据2 -> 从机应答 ->停止信号
    //========================================================================
    // 描述: IIC通信中断服务函数 包括发送和接收
    // 参数: none.
    // 返回: none.
    //========================================================================
    void I2C_Isr() interrupt 24 //IIC中断函数
    {
    //	printf("无条件接收IICRXT:%X\r\n", I2CRXD);	 //接收到0x44 为开始信号或停止信号的返回值 
     _push_(P_SW2);//将 切换控制寄存器 进栈处理
     P_SW2 |= 0x80; 
    if (I2CSLST & 0x40) //收到开始信号
     {
    //	printf("START\r\n");
    
    	I2CSLST &= ~0x40; //开始信号清零 STAIF 位清零
     } 	else if (I2CSLST & 0x20) //从机模式时接收到 1 字节的数据后的中断请求位
     {
    	 I2CSLST &= ~0x20; //1 字节的数据 RXIF 位清零						
    	 if (isda) //设备地址
    	 {
    		isda = 0; //处理 RECV 事件(设备地址)
    		deviceID_addr = I2CRXD;
    //		printf("设备地址:%X\r\n",deviceID_addr);
    	 }
    	 else if (isma)//寄存器地址
    	 {
    		 isma = 0; //处理 RECV 事件(寄存器地址)
    		 memory_addr = I2CRXD;
    		 IICdata_addr =0;
    //		 printf("寄存器地址:%X\r\n",memory_addr);
    	 }//由于初始化的时候,IIC接收所有设备地址 ,不过从这里可继续添加  else if 语句进行判断特点指令
    	 else//数据1 和 数据2
    	 {
    		if(IICdata_addr >= 2) IICdata_addr = 0;
    		buffer[IICdata_addr++] = I2CRXD; //处理 RECV 事件(数据1 和 数据2)
    //		printf("打印出_buffer:%X\r\n", buffer[IICdata_addr++]);
    	 }
     } 	else if (I2CSLST & 0x10)//从机模式时发送完成 1 字节的数据后的中断请求位
     {
    
    			I2CSLST &= ~0x10; //处理 SEND 事件 						从机模式时发送完成1字节的数据后的中断请求位
    
    	 
    	 if (I2CSLST & 0x02)//从机模式时,接收到的 ACK 数据
    	 {
    //		I2CTXD = 0xff; //接收到 NAK 则停止读取数据   
    	 }
    	 else
    	 {	//接收到 ACK 则继续读取数据 (重点)可持续发送 数据出去 主机觉得不断开
    
    		 if(deviceID_addr == 0xC3) //判断是否发出了24个字节 这里是我芯片特定的规律
    		 {
    			 I2CTXD = buffer1_24byte[++Read_organize_one];
    			 if(Read_organize_one >= 24)
    			 {
    				 //printf("打印出_I2CTXD:%X ADD:%d\r\n", buffer1_24byte[Read_organize_one-1],Read_organize_one-1); //打印会影响数据输出准确性
    				 Read_organize_one = 0;
    				 I2CSLST &= ~0x10; //处理 SEND 事件  					从机模式时发送完成1字节的数据后的中断请求位
    				 I2CSLST &= ~0x08; //处理 STOP 事件						从机模式时接收到STOP信号后的中断请求位
    			 }
    		 }
    		 if(deviceID_addr == 0xC5) //判断是否发出了24个字节	这里是我芯片特定的规律
    		 {
    			 I2CTXD = buffer2_24byte[++Read_organize_two];
    			 if(Read_organize_two >= 24)
    			 {
    				 Read_organize_two = 0;
    				 I2CSLST &= ~0x10; //处理 SEND 事件 					从机模式时发送完成1字节的数据后的中断请求位
    				 I2CSLST &= ~0x08; //处理 STOP 事件						从机模式时接收到STOP信号后的中断请求位
    			 }	 
    		 }		 
    	 }
     } else if (I2CSLST & 0x08)//从机模式时接收到 STOP 信号后的中断请求位
     {
    //	 printf("STOP\r\n");
    	 I2CSLST &= ~0x08; //处理 STOP 事件
    	 isda = 1;//设备地址
    	 isma = 1; //寄存器地址
    	 CBM128S085_start = 1;
    	 Read_organize_one = 0;
    	 Read_organize_two = 0;
     }
     _pop_(P_SW2);//出栈处理
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    使用printf打印出信息的时候,最好不要在IIC中断里放置会出现打印出来的数据不对,最好是在主程序的死循环中放置
    注意变量溢出的问题不然会死机

    //		printf("设备地址: %X\r\n",deviceID_addr);
    //		printf("寄存器地址: %X\r\n",memory_addr);
    //		printf("buffer寄存器:%X\r\n",buffer[0]);
    //		printf("buffer寄存器:%X\r\n",buffer[1]);
    
    • 1
    • 2
    • 3
    • 4

    打印16进的时候,%后面用 “x"会发现多了一个字节,但这个字节是不属于其变量的,这样会让人产生错觉。所以要使用"bx”

    		printf("设备地址: %bX\r\n",deviceID_addr);
    		printf("寄存器地址: %bX\r\n",memory_addr);
    		printf("buffer寄存器:%bX\r\n",buffer[0]);
    		printf("buffer寄存器:%bX\r\n",buffer[1]);
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    快速上手 Docker Swarm:构建分布式容器集群、轻松管理节点和服务
    JavaScript事件循环
    网络攻防实验 (by quqi99)
    工会排队奖励模式:企业家眼中的新机遇
    [论文笔记] ICLR 2022 | 减少跨语言表示差异,字节跳动AI Lab通过流形混合增强跨语言迁移
    2022牛客多校1
    史诗级外挂,肝完这份 MQ+ 分布式事务套餐,其实阿里 P8 你也值得
    十四天学会C++之第二天(函数和库)
    chrome浏览器设置--disable-web-security解决跨域
    R语言—随机抽样
  • 原文地址:https://blog.csdn.net/weixin_41226265/article/details/126800500