中断与轮询两种方式驱动IIC

中断

中断可以看作是一种“硬件轮询”。即本质上,CPU会通过读取外部信号来判断CPU的下一步状态。
所谓的“硬件轮询”可以用单片机理解
单片机中的中断接口
效果:当按键按下时,蜂鸣器就会响,不松开就一直响,松开关闭。

(主程序死循环,通过CPU中断可以暂时中断,先执行其他任务,然后再回来继续执行被中断的任务。例子中开启外部中断0,中断方式为下降沿触发,比如控制端口原来是高电平的,按下按钮使控制端口变为低电平,高电平到低电平有个下降过程,下降沿触发中断0,调用中断服务处理函数,蜂鸣器响。中断服务处理函数有个循环检测直到按钮释放才关闭蜂鸣器,退出中断服务处理函数,控制端口恢复为高电平。)

中断处理方式

设备管理中,高速的处理器和低速的输入输出设备相对来说,会降低整体效率,为了减少程序直接控制方式中CPU的等待时间,提高系统的并行工作程度,采用中断处理方式是很有必要的。

在I/O设备中断方式下,CPU与I/O设备之间数据的传输步骤如下:

1.在某个进程需要数据时,发出指令启动输入输出设备,准备要处理的数据;
2.在进程发出指令启动设备之后,该进程放弃处理器,等待相关I/O操作完成。此时,进程调度程序会调度其他就绪进程使用处理器。
3.当I/O操作完成时,输入输出设备控制器通过中断请求线向处理器发出中断信号,处理器收到中断信号之后,转向预先设计好的中断处理程序,对数据传送工作进行相应的处理。
4.得到了数据的进程,转入就绪状态。在随后的某个时刻,进程调度程序会选中该进程继续工作。

在这里插入图片描述
那么发生中断时CPU怎么知道程序的地址?
通过映射的关系找到对应程序的地址。
例如在x86架构中,中断向量表的位置保存在IDTR寄存器里,CPU通过这个寄存器就能找到中断向量表,然后根据中断号就可以找到具体的中断入口了
中断方式的优缺点

优点:
I/O设备中断方式使处理器的利用率显著提高;
支持多道程序和I/O设备的并行操作,提高了效率。

缺点:
各种各样的输入输出设备通过中断处理方式进行并行操作,使中断次数增加,会造成CPU无法响应中断;
如果在缓冲区装满数据之后发生中断。那么在数据传送过程中,发生中断的机会较多,将耗去大量的CPU处理时间。

IIC中断方式驱动PCA9534

在这里插入图片描述

其中初始化的两个函数分别是

Config = XIic_LookupConfig(DeviceID);
Config = XIic_CfgInitialize(DeviceID);

具体的配置是

XIic_Config XIic_ConfigTable[XPAR_XIIC_NUM_INSTANCES] =
{
	{
		XPAR_AXI_IIC_0_DEVICE_ID,
		XPAR_AXI_IIC_0_BASEADDR,
		XPAR_AXI_IIC_0_TEN_BIT_ADR,
		XPAR_AXI_IIC_0_GPO_WIDTH
	},
	{
		XPAR_AXI_IIC_1_DEVICE_ID,
		XPAR_AXI_IIC_1_BASEADDR,
		XPAR_AXI_IIC_1_TEN_BIT_ADR,
		XPAR_AXI_IIC_1_GPO_WIDTH
	}
};

/*
	 * Set default values and configuration data, including setting the
	 * callback handlers to stubs  so the system will not crash should the
	 * application not assign its own callbacks.
	 */
	InstancePtr->IsStarted = 0;
	InstancePtr->BaseAddress = EffectiveAddr;
	InstancePtr->RecvHandler = XIic_StubHandler;
	InstancePtr->RecvBufferPtr = NULL;
	InstancePtr->SendHandler = XIic_StubHandler;
	InstancePtr->SendBufferPtr = NULL;
	InstancePtr->StatusHandler = XIic_StubStatusHandler;
	InstancePtr->Has10BitAddr = Config->Has10BitAddr;
	InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
	InstancePtr->Options = 0;
	InstancePtr->BNBOnly = FALSE;
	InstancePtr->GpOutWidth = Config->GpOutWidth;
	InstancePtr->IsDynamic = FALSE;
	InstancePtr->IsSlaveSetAckOff = FALSE;

	/*
	 * Reset the device.
	 */
	XIic_Reset(InstancePtr);

	XIic_ClearStats(InstancePtr);

其中ConfigTable中的一些及地址是在我们配置完BlockDesign后VIVADO自动生成的,一般不会有什么差错,但是在调试的过程中如果出现调试不通的情况,可以在当作备选项检查一下。CfgInitialize()的核心是将寄存器的值进行复位。
i2c_reg8_write16() 是我们自己封装的一个函数,其主要作用是将要发送的地址和数据放入
sent_buf
后,再调用 *XIic_Send(UINTPTR BaseAddress, u8 Address u8 BufferPtr, unsigned ByteCount, u8 Option) 这个函数中。有关基于中断的IIC发送数据的程序有很多,但是核心基本上都是这个函数。
这个函数内部做了许多操作,比如等待BUS free,将地址写入待发送的fifo并表明接下来是写操作,配置中断(清楚中断的锁存状态,向中断寄存器中写入数据),发送数据(send_data()),释放总线等操作。

PCA9534操作简述

PCA9534A 包含一个 8 位配置(输入或输出可选)、输入端口、输出端口和极性反转(高电平有效或低电平有效)寄存器。在加电时,I/O 被配置为输入。但是,系统主控制器可以通过写入 I/O 配置位将 I/O 启用为输入或输出。每个输入或输出的数据均保存在相应的输入或输出寄存器中。输入端口寄存器的极性可借助极性反转寄存器进行转换。所有寄存器都可由系统主控器读取。
在这里插入图片描述
在这里插入图片描述
简单来说,PCA9534就是一个将IIC串行输入的数据转化为并行输出的数据。
在这里插入图片描述
为了将PCA9534的引脚配置为输出,需要向其命令字节写入11111111。这也是我们PCA9354_GPIO_sta_init() 所进行的操作。

轮询

轮询方式主要是每隔一段时间对各种设备进行轮询,查询设备有无处理要求,若有处理要求则进行相应处理。由此可见,若设备无处理要求,则 CPU 仍然会查询设备状态。而轮询的过程将会占据 CPU 的一部分处理时间,因此,程序轮询是一种效率较低的处理方式。

串口的轮询实现就是通过不停的轮询状态寄存器的状态判断是否有数据需要接收或发送。发送时先向数据寄存器或发送FIFO写入数据,然后不断检查状态寄存器,查看发送是否完成。发送完成才能发送下一字节或退出发送状态。对于接收则要先创建一个循环定时器或线程死循环,不断的轮询状态寄存器,检查是否有数据收到,有数据收到则读取数据,然后调用接收回调,将数据传递给上层应用。

轮询模式下,发送CPU耗时略大于数据在串口线上传输的时间,要知道串口的波特率相对于CPU主频来讲要慢百万倍以上。而接收时,轮询频率越高则无用的CPU耗时越多,轮询频率越低则接收响应时间越长,两者不能得兼。
其操作核心函数是
在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
stm8si2c程序,调试通过 INTERRUPT_HANDLER(I2C_IRQHandler, 19) { /* In order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction. */ struct SCB_T *system=&system_process; unsigned char i,i2c_sr1,i2c_sr2,i2c_event,i2c__status=0,temp,sr1_analysis_int_resource[8],sr2_analysis_int_resource[8]; char i2c_interrupt_type=0,p;//在一次I2中断中,I2C中断中的中断标志位个数; disableInterrupts();//关总中断 i2c_sr1=I2C->SR1; p=I2C->SR3; i2c_sr2=I2C->SR2; //temp=I2C->SR3; //analysis interrupt resource in i2c->sr1 register sr1_analysis_int_resource[0]=i2c_sr1&I2C_SR1_SB; sr1_analysis_int_resource[1]=i2c_sr1&I2C_SR1_ADDR; sr1_analysis_int_resource[2]=i2c_sr1&I2C_SR1_BTF; sr1_analysis_int_resource[3]=i2c_sr1&I2C_SR1_ADD10; sr1_analysis_int_resource[4]=i2c_sr1&I2C_SR1_STOPF; // sr1_i2c__state[5]=i2c_state&((u8)I2C_SR1_BIT6); sr1_analysis_int_resource[6]=i2c_sr1&I2C_SR1_RXNE; sr1_analysis_int_resource[7]=i2c_sr1&I2C_SR1_TXE; //analysis interrupt resource in i2c->sr2 register sr2_analysis_int_resource[0]=i2c_sr2&I2C_SR2_BERR; sr2_analysis_int_resource[1]=i2c_sr2&I2C_SR2_ARLO; sr2_analysis_int_resource[2]=i2c_sr2&I2C_SR2_AF; sr2_analysis_int_resource[3]=i2c_sr2&I2C_SR2_OVR; sr2_analysis_int_resource[5]=i2c_sr2&I2C_SR2_WUFH; if(sr1_analysis_int_resource[0]==I2C_SR1_SB) {i2c__status=0x01;i2c_interrupt_type++;} if(sr1_analysis_int_resource[1]==I2C_SR1_ADDR) {i2c__status=0x02;i2c_interrupt_type++;} if(sr1_analysis_int_resource[2]==I2C_SR1_BTF) {i2c__status=0x03;i2c_interrupt_type++;} if(sr1_analysis_int_resource[3]==I2C_SR1_ADD10) {i2c__status=0x04;i2c_interrupt_type++;} if(sr1_analysis_int_resource[4]==I2C_SR1_STOPF) {i2c__status=0x05;i2c_interrupt_type++;} if(sr1_analysis_int_resource[6]==I2C_SR1_RXNE) {i2c__status=0x06;i2c_interrupt_type++;} if(sr1_analysis_int_resource[7]==I2C_SR1_TXE) {i2c__status=0x07;i2c_interrupt_type++;} if(sr2_analysis_int_resource[0]==I2C_SR2_BERR) {i2c__status=0x08;i2c_interrupt_type++;} if(sr2_analysis_int_resource[1]==I2C_SR2_ARLO) {i2c__status=0x09;i2c_interrupt_type++;} if(sr2_analysis_int_resource[2]==I2C_SR2_AF) {i2c__status=0x0a;i2c_interrupt_type++;} if(sr2_analysis_int_resource[3]==I2C_SR2_OVR) {i2c__status=0x0b;i2c_interrupt_type++;} if(sr2_analysis_int_resource[5]==I2C_SR2_WUFH) {i2c__status=0x0c;i2c_interrupt_type++;} if(i2c_interrupt_type>=2) /*there are more than one interrupt resource in the time*/ { if(i2c_interrupt_type==2) { if((sr1_analysis_int_resource[1]==I2C_SR1_ADDR)&&(sr1_analysis_int_resource[7]==I2C_SR1_TXE)) { I2C->DR=system->i2c.send_frame.data[system->i2c.send_frame.proc]; system->i2c.send_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x62; } else if((sr1_analysis_int_resource[7]==I2C_SR1_TXE)&&(sr1_analysis_int_resource[2]==I2C_SR1_BTF)) { system->i2c.send_frame.terminate=0; //set I2C transfer terminate bit; system->i2c.send_frame.mod=0; system->i2c.send_frame.write=0; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x64; } else if((sr1_analysis_int_resource[7]==I2C_SR1_TXE)&&(sr2_analysis_int_resource[2]==I2C_SR2_AF)) { I2C->CR2|=I2C_CR2_STOP; I2C->SR2&=(~I2C_SR2_AF);//clear AF bit; system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x64; } else { system->i2c.error=1; I2C_ITConfig(I2C_IT_EVT, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x37; } } else { system->i2c.error=1; I2C_ITConfig(I2C_IT_EVT, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x37; } } else { switch(i2c__status) { case I2C_SR1_SB_proc: //如果是发送模式 if(system->i2c.send_frame.mod==1)//说明本次中断之前是从模式,说明这是在从模式下发的起始位; { //EV5 p=I2C->SR1; I2C->DR=system->i2c.send_frame.add__L; //自动清除I2C_SR1_SB标志 system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x38; } else { if(system->i2c.rev_frame.mod==1) //说明本次中断之间是主模式,这次发的是重复起始位; { //EV6如果是接收模式 p=I2C->SR1; I2C->DR=system->i2c.rev_frame.add__L;//自动清除I2C_SR1_SB标志; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x51; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x36; } } break; case I2C_SR1_ADDR_proc: p=I2C->SR1; temp=I2C->SR3;//软件读取SR1寄存器后,对SR3寄存器的读操作将清除该位 temp&=(u8)I2C_SR3_TRA; I2C->CR2|=(u8)I2C_CR2_ACK;// 使能应答位 I2C->CR2&=(u8)(~I2C_CR2_POS);//设置接受到当字节应答 //如果是发送模式 if(system->i2c.send_frame.mod==1) { if(temp==(u8)I2C_SR3_TRA) {; } else { system->i2c.error=1; } } else { if(system->i2c.rev_frame.mod==1) { if(temp==0)//machine at a master-receive mod { system->i2c.rev_frame.proc=0; } else { system->i2c.error=1; } } else { system->i2c.error=1; } } system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x52; break; case I2C_SR1_RXNE_proc: if(system->i2c.rev_frame.proci2c.rev_frame.num-3)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x57; } else if(system->i2c.rev_frame.proc==(u8)(system->i2c.rev_frame.num-2)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x58; I2C->CR2&=(u8)(~I2C_CR2_ACK);//不返回应答 I2C->CR2|=I2C_CR2_STOP; //发停止位结束这次数据接收; } else if(system->i2c.rev_frame.proc>=(u8)(system->i2c.rev_frame.num-1)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x59; system->i2c.rev_frame.terminate=0; //set I2C transfer terminate bit; system->i2c.rev_frame.mod=0; system->i2c.rev_frame.read=0; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfb; } break; case I2C_SR1_TXE_proc: if(system->i2c.send_frame.proci2c.send_frame.num-1)) { I2C->DR=system->i2c.send_frame.data[system->i2c.send_frame.proc]; system->i2c.send_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x61; } else if(system->i2c.send_frame.proc=(u8)(system->i2c.send_frame.num)) { I2C->CR2|=I2C_CR2_STOP; // 发停止位结束 这次数据接收; I2C_ITConfig(I2C_IT_BUF, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x60; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfc; } break; case I2C_SR2_AF_proc: I2C->CR2|=I2C_CR2_STOP; I2C->SR2&=(~I2C_SR2_AF);//clear AF bit; system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x63; break; default: system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfd; break; } } system->i2c.int_debug_count++; enableInterrupts();//开总中断 }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值