应广单片机系列——用I2C接口读写EEPROM

描述

注:本文是作者以前发表在其个人博客,现在发布到电子发烧友专栏


      本例是用针对标准I2C接口EEPROM存储器24C02进行读写操作,只要对例程做适当修改,就可以用到大部分控制I2C接口设备的场合。

应广单片机软件I2C接口例程(MASTER模式)

本例仅供参考,欢迎指正程序中的问题

//-----------------------------------------
.chip p201cs14a
//{{PADAUK_CODE_OPTION
 .Code_Option Bootup  Slow  // 1024 ILRC
 .Code_Option LVD  2.79V  // Maximum performance = 4 MIPS
 .Code_Option Security Enable  // Security 3/4 words Enable
//}}PADAUK_CODE_OPTION


//定义I2C接口
I2C_SDA equ pa.7
I2C_SCL equ pa.6
I2C_SDA_DIR equ pac.7
I2C_SCL_DIR equ pac.6
I2C_LONG_DLY equ 50
I2C_SHORT_DLY equ 20
I2C_SDA_HIGH equ set1 I2C_SDA 
I2C_SDA_LOW equ set0 I2C_SDA
I2C_SCL_HIGH equ set1 I2C_SCL
I2C_SCL_LOW equ set0 I2C_SCL
I2C_SDA_OUTPUT equ set1 I2C_SDA_DIR
I2C_SDA_INPUT equ set0 I2C_SDA_DIR
I2C_SCL_OUTPUT equ set1 I2C_SCL_DIR
I2C_SCL_INPUT equ set0 I2C_SCL_DIR


//定义I2C变量
byte i2c_rw_addr //读写地址
byte i2c_rw_byte //读写数据
byte i2c_rw_cmd //读写的器件地址
byte i2c_rw_temp //读写过程中间变量
byte i2c_rw_cnt //读写过程中间变量

//
byte Xms
byte ms_cnt

//
byte test_addr
byte test_data

.romadr 0x000
 goto main0
 goto main1

.romadr 0x010
isr_entry:
 pushaf
 intrq = 0
 popaf
 reti


//----------------------------
//产生START信号
//----------------------------
i2c_start:
 I2C_SDA_OUTPUT
 I2C_SCL_OUTPUT
 I2C_SDA_HIGH
 delay I2C_LONG_DLY
 I2C_SCL_HIGH
 delay I2C_LONG_DLY
 I2C_SDA_LOW
 delay I2C_LONG_DLY
 I2C_SCL_LOW
 delay I2C_LONG_DLY
 ret

//----------------------------
//产生STOP信号
//----------------------------
i2c_stop:
 I2C_SCL_LOW
 delay I2C_LONG_DLY
 I2C_SDA_LOW
 delay I2C_LONG_DLY
 I2C_SCL_HIGH
 delay I2C_LONG_DLY
 I2C_SDA_HIGH
 delay I2C_LONG_DLY
 //
 I2C_SCL_INPUT
 I2C_SDA_INPUT
 ret


//----------------------------
//检查SALVE ACK信号
//----------------------------
i2c_slave_ack:
 //don't check ACK
 I2C_SDA_INPUT
 delay I2C_SHORT_DLY
 I2C_SCL_HIGH
 delay I2C_SHORT_DLY
 I2C_SCL_LOW
 delay I2C_SHORT_DLY
 I2C_SDA_OUTPUT
 I2C_SDA_LOW
 delay I2C_SHORT_DLY
 ret

//----------------------------
//输出MASTER ACK信号
//----------------------------
i2c_master_ack:
 I2C_SDA_OUTPUT
 I2C_SDA_LOW
 delay I2C_SHORT_DLY
 I2C_SCL_HIGH
 delay I2C_SHORT_DLY
 I2C_SCL_LOW
 delay I2C_SHORT_DLY
 ret

//----------------------------
//输出MASTER NACK信号
//----------------------------
i2c_master_nack:
 I2C_SDA_OUTPUT
 I2C_SDA_HIGH
 delay I2C_SHORT_DLY
 I2C_SCL_HIGH
 delay I2C_SHORT_DLY
 I2C_SCL_LOW
 delay I2C_SHORT_DLY
 ret


//------------------------------
//写一个字节
//Input: i2c_rw_temp
//Used:  i2c_rw_cnt
//------------------------------
i2c_write_8bit:
 i2c_rw_cnt = 8
i2c_write_8bit_loop:
 slc i2c_rw_temp
 swapc I2C_SDA
 delay I2C_SHORT_DLY
 I2C_SCL_HIGH
 delay I2C_SHORT_DLY
 I2C_SCL_LOW
 delay I2C_SHORT_DLY
 dzsn i2c_rw_cnt
 goto i2c_write_8bit_loop
 ret

//------------------------------
//读一个字节
//Used:   i2c_rw_cnt
//Output: i2c_rw_temp
//------------------------------
i2c_read_8bit:
 i2c_rw_temp = 0
 i2c_rw_cnt = 8
 delay I2C_SHORT_DLY
i2c_read_8bit_loop:
 I2C_SCL_HIGH
 delay I2C_SHORT_DLY
 swapc I2C_SDA
 slc i2c_rw_temp
 I2C_SCL_LOW
 delay I2C_SHORT_DLY
 dzsn i2c_rw_cnt
 goto i2c_read_8bit_loop
 ret

//------------------------------
//Input:  i2c_rw_addr
//        i2c_rw_cmd
//Used:   i2c_rw_cnt
//        i2c_rw_temp
//Output: i2c_rw_byte
//------------------------------
i2c_read_byte:
 //start
 call i2c_start

 //write device address(write)
 i2c_rw_temp = i2c_rw_cmd
 call i2c_write_8bit

 //slave ack
 call i2c_slave_ack

 //write register address
 i2c_rw_temp = i2c_rw_addr
 call i2c_write_8bit

 //slave ack
 //don't check ACK
 call i2c_slave_ack

 //start repeat
 call i2c_start

 //write device address(read)
 i2c_rw_temp = i2c_rw_cmd
 i2c_rw_temp.0 = 1
 call i2c_write_8bit

 //slave ack
 //don't check ACK
 I2C_SDA_INPUT
 delay I2C_SHORT_DLY
 I2C_SCL_HIGH
 delay I2C_SHORT_DLY
 I2C_SCL_LOW
 delay I2C_SHORT_DLY //这里为特殊情况I2C_SDA不用转为输出

 //read data
 i2c_rw_temp = 0
 call i2c_read_8bit
 i2c_rw_byte = i2c_rw_temp //store data

 //master nack
 call i2c_master_nack

 //stop
 call i2c_stop

 //retune
 delay I2C_LONG_DLY
 wdreset
 ret

//------------------------------
//Input:  i2c_rw_addr
//        i2c_rw_byte
//        i2c_rw_cmd
//Used:   i2c_rw_cnt
//        i2c_rw_temp
//------------------------------
i2c_write_byte:
 //start
 call i2c_start

 //write device address
 i2c_rw_temp = i2c_rw_cmd
 call i2c_write_8bit

 //slave ack
 //don't check ACK
 call i2c_slave_ack

 //write register address
 i2c_rw_temp = i2c_rw_addr
 call i2c_write_8bit

 //slave ack
 //don't check ACK
 call i2c_slave_ack

 //write data
 i2c_rw_temp = i2c_rw_byte
 call i2c_write_8bit

 //slave ack
 //don't check ACK
 call i2c_slave_ack

 //stop
 call i2c_stop

 //retune
 delay I2C_LONG_DLY
 wdreset
 ret

EEPROM_RW_CMD equ 0xA0
//------------------------------
//函数名: eeprom_read_byte
//Input:  i2c_rw_addr
//Used:   i2c_rw_cnt
//        i2c_rw_temp
//Output: i2c_rw_byte
//------------------------------
eeprom_read_byte:
 i2c_rw_cmd = EEPROM_RW_CMD
 goto i2c_read_byte //注意这里用的是跳转
//------------------------------
//函数名: eeprom_write_byte
//Input:  i2c_rw_addr
//        i2c_rw_byte
//Used:   i2c_rw_cnt
//        i2c_rw_temp
//注意:  调用完后需要等待一段时间以保证写操作完成
//------------------------------
eeprom_write_byte:
 i2c_rw_cmd = EEPROM_RW_CMD
 goto i2c_write_byte //注意这里用的是跳转

 

//----------------------------------------
//input: ms
//该函数以4M频率为基准时钟实现延时
//----------------------------------------
delayXms:
 while(Xms)
 {
  wdreset
  ms_cnt = 20
  while(ms_cnt)
  {
   delay 195
    ms_cnt--
  }
  Xms--
 }
 ret

 

main0:
 .ADJUST_OTP_IHRCR 8MIPS  // IHRC/2 = 8MIPS, WatchDog Disable, RAM 0,1 temporary be used
 sp = 0x30

 disgint
 inten = 0


 pa = 0b0000_0000
 paph = 0b1101_0000
 pac = 0b0000_0001 
 pb = 0b0000_0000
 pbph = 0b0000_0000
 pbc = 0b1111_1111

 I2C_SDA_INPUT
 I2C_SCL_INPUT

 delay 200

 mov a,0b100_11_111
 mov t16m,a

 clkmd.1 = 1 //enable watch dog
 wdreset


 Xms = 100
 call delayXms

 

 test_data = 0
 test_addr = 0

main0_loop:
 wdreset

 //写E2EPROM
 i2c_rw_addr = test_addr
 i2c_rw_byte = test_data
 call eeprom_write_byte

 //调用EEPROM写操作函数后要等待一段时间,以保证数据写操作完成
 Xms = 20
 call delayXms

 //读E2EPROM
 i2c_rw_addr = test_addr
 call eeprom_read_byte
 if(i2c_rw_byte != test_data)
 {
  //读回的数据比较出错,判断为读写E2PROM出错
  nop
 }

 test_addr ++
 test_data --
 

 goto main0_loop

//----------------FPPA1-------------------
main1: 
 sp = 52
main1_loop:
 goto main1_loop

 

本例代码是从实际程序中移植而来,已编译,未做最终调试


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
Phil2222 2020-12-08
0 回复 举报
智障 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分