STC8H_硬件IIC

本文介绍了STC8H系列单片机在硬件IIC通信中的应用,详细解析了I2C配置寄存器、从机状态寄存器、从机地址寄存器和数据寄存器的使用,并展示了IIC从机初始化及中断服务函数的代码实现。文章还提到了STC公司在标准IIC协议中的两种机制更改,以及如何处理IIC中断事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原理图部分

使用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;}     //高阻输入

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];

}

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);//出栈处理
}

使用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]);

打印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]);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谢谢~谢先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值