I2C 学习

http://blog.csdn.net/firefly_cjd/article/details/51921129

1、启动时序

红色阴影区表示启动信号


2、停止信号


3、IIC写一个字节




4、应答位ACK

SDA driven LOW by M1170 for one clock cycle when SCL is HIGH

XR20M1170IG16TR

I2C与SPI的选择:I2C-bus or SPI interface select.  I2C-bus interface is selected if this pin is HIGH.  SPI interface is selected if this pin is LOW
高电平为I2C,低电平为SPI

IRQ#: 中断信号    Interrupt output (open-drain, active LOW). 
低电平有效

RESET#:复位信号 Reset (active LOW) - A longer than 40 ns LOW  pulse on this pin will reset the internal registers and  all outputs.
    超过40ns的低电平脉冲

配置寄存器: 16550 UART兼容性控制、状态和数据传输

激活方向控制功能:set EFCR bit-4 to “1”
This pin is HIGH for receive state and LOW for transmit state.

时钟产生的两种方法:
external 24 MHz crystal on pins XTAL1 and XTAL2, or external clock source of up to 64 MHz on XTAL1 pin

TX FIFO is full 回复negative acknowledge:
SDA driven HIGH by M1170 for one clock cycle when SCL is HIGH

读和写的判定:
If bit-0 is’0’, then it is a write transaction.  If bit-0 is ’1’, then it is a read transaction

THR/RHR:数据保持寄存器
ISR/IER:中断状态与控制寄存器
FCR:FIFO控制寄存器
LSR/LCR:接收线路状态与控制寄存器
MSR/MCR:调制解调器状态与控制寄存器
DLL/DLM/DLD:可编程数据速率(时钟)除数寄存器
SPR:用户可访问暂存寄存器
MCR:分频控制寄存器,Bit 7(1~4)
BAUD RATE GENERATOR框图

问题

1、如下图所示,本机硬件选用的是GND-GND的接法,为何不选用SDA-GND的接法


2、下图为子地址的格式,如何知道子地址是多少


3、什么情况下发中断













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();//开总中断 }
首先需要了解一下SS1623的时序要求,根据其时序要求,可以自定义PB7和PB9口的IIC驱动程序。以下是一份基于HAL库的代码示例: ```c #include "stm32f1xx_hal.h" #define IIC_SCL_PIN GPIO_PIN_7 #define IIC_SDA_PIN GPIO_PIN_9 #define IIC_SCL_GPIO GPIOB #define IIC_SDA_GPIO GPIOB #define IIC_SCL_HIGH() HAL_GPIO_WritePin(IIC_SCL_GPIO, IIC_SCL_PIN, GPIO_PIN_SET) #define IIC_SCL_LOW() HAL_GPIO_WritePin(IIC_SCL_GPIO, IIC_SCL_PIN, GPIO_PIN_RESET) #define IIC_SDA_HIGH() HAL_GPIO_WritePin(IIC_SDA_GPIO, IIC_SDA_PIN, GPIO_PIN_SET) #define IIC_SDA_LOW() HAL_GPIO_WritePin(IIC_SDA_GPIO, IIC_SDA_PIN, GPIO_PIN_RESET) #define IIC_SDA_READ() HAL_GPIO_ReadPin(IIC_SDA_GPIO, IIC_SDA_PIN) void IIC_Delay(uint16_t us) { uint16_t i = 0; while (us--) { i = 10; while (i--) ; } } void IIC_Start(void) { IIC_SDA_HIGH(); IIC_SCL_HIGH(); IIC_Delay(4); IIC_SDA_LOW(); IIC_Delay(4); IIC_SCL_LOW(); IIC_Delay(4); } void IIC_Stop(void) { IIC_SCL_LOW(); IIC_SDA_LOW(); IIC_Delay(4); IIC_SCL_HIGH(); IIC_Delay(4); IIC_SDA_HIGH(); IIC_Delay(4); } void IIC_Ack(void) { IIC_SCL_LOW(); IIC_SDA_LOW(); IIC_Delay(4); IIC_SCL_HIGH(); IIC_Delay(4); IIC_SCL_LOW(); IIC_Delay(4); } void IIC_NAck(void) { IIC_SCL_LOW(); IIC_SDA_HIGH(); IIC_Delay(4); IIC_SCL_HIGH(); IIC_Delay(4); IIC_SCL_LOW(); IIC_Delay(4); } uint8_t IIC_WaitAck(void) { uint8_t ucErrTime = 0; IIC_SCL_LOW(); IIC_SDA_HIGH(); IIC_Delay(1); IIC_SCL_HIGH(); IIC_Delay(1); while (IIC_SDA_READ()) { ucErrTime++; if (ucErrTime > 250) { IIC_Stop(); return 1; } } IIC_SCL_LOW(); return 0; } void IIC_SendByte(uint8_t ucData) { uint8_t i = 8; while (i--) { IIC_SCL_LOW(); if (ucData & 0x80) IIC_SDA_HIGH(); else IIC_SDA_LOW(); ucData <<= 1; IIC_Delay(2); IIC_SCL_HIGH(); IIC_Delay(2); } IIC_SCL_LOW(); } uint8_t IIC_ReadByte(uint8_t ucAck) { uint8_t i = 8; uint8_t ucData = 0; IIC_SCL_LOW(); IIC_SDA_HIGH(); IIC_Delay(1); while (i--) { IIC_SCL_HIGH(); IIC_Delay(1); ucData <<= 1; if (IIC_SDA_READ()) ucData++; IIC_SCL_LOW(); IIC_Delay(1); } if (ucAck) IIC_Ack(); else IIC_NAck(); return ucData; } void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStruct.Pin = IIC_SCL_PIN | IIC_SDA_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(IIC_SCL_GPIO, &GPIO_InitStruct); IIC_SDA_HIGH(); IIC_SCL_HIGH(); } ``` 在上面的代码中,我们定义了PB7和PB9口分别对应IIC的SCL和SDA信号线。然后定义了几个宏,分别用于设置SCL和SDA口的电平状态。接着定义了一些IIC总线操作的函数,比如发送开始信号、停止信号、ACK信号、NAck信号、等待ACK信号、发送数据字节以及读取数据字节等。 最后,在IIC_Init函数中,我们使用HAL库的GPIO_InitTypeDef结构体来初始化PB7和PB9口的状态,设置为开漏输出,并将SDA口的电平状态设置为高电平。 有了这份代码,我们就可以使用PB7和PB9口的IIC驱动SS1623了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值