0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

应广单片机系列——高速I2C接口

聚丰开发 2018-10-16 18:45 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

经过一段时间的慎重考虑,在诸多朋友的支持下,决定在接下来的日子里,会尽可能多的写一些关于应广多核单片机应用的文章,希望能给有兴趣学习了解应广单片机的朋友提供到点滴帮助。

这个针对应广双核、多核单片机应用的系列,会以具体程序为例,在程序中加以注释,只要条件允许,例程都会经过调试,如果只是编译没有调试的,我会注明。

附件中的例程代码,读者可以自由使用,不需要通知我,如有可能,希望在代码中保留我的签名信息,深表感谢!

例程为利用应广单片机的特点,用软件实现理论速率可以达到1M的I2C通讯接口,如果是其它普通单片机,也可以用软件模拟出高速I2C,不同点是应广实现模拟后还能够实现各种控制功能,而其它普通单片则不能。


//-----------------------------------------
//应广单片机软件实现高速I2C接口例程(SALVE模式)
//本例仅供参考,欢迎指正程序中的问题
//本例利用应广单片机的双核特点
//用一个核专门对I2C接口的IO进行扫描等待
//对I2C接口的高低变化利用应广特有的IO状态等待指令高速实现IO口跳变判断
//利用定时器
进行超时判断
//理论上可以让模拟的I2C接口达到1M的速率
//2012年12月15日
//
//作者:戴上举
//邮箱:daishangju@163.com
//博客:forum.eet-cn.com/BLOG_daishangju_334.HTM
//电话:13509678051
//Q Q:1514292225
//-----------------------------------------

.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接口要用的IO口,用户可以自己修改这里的IO口定义
I2C_SDA equ pa.0
I2C_SDA_LOW equ set0 I2C_SDA
I2C_SDA_HIGH equ set1 I2C_SDA
I2C_SDA_INPUT equ set0 pac.0
I2C_SDA_OUTPUT equ set1 pac.0
I2C_SCL equ pa.4
//定义I2C设备地址,用户可以自己修改此地址
I2C_READ_CMD equ 0x7F
I2C_WRITE_CMD equ 0x7E


word init_timer

//byte Xms
//byte ms_cnt

byte i2c_device //用来存放I2C接口地址
byte i2c_write_byte //I2C进行写操作时存放I2C写入的数据
byte i2c_read_byte //I2C进行读操作时候读出的内容

bit i2c_start_flag

//应广单片机程序入口,第一条必须为跳转到第一个内核主程序入口地址的指令,第二条为第二个内核,有几个内核就有几条
.romadr 0x000
goto main0
goto main1


//应广单片机中断程序入口地址,所有中断共用同一个入口,需要用户自己判断中断类型
.romadr 0x010
pushaf //压栈
if(intrq.T16) //判断是否为定时中断
{
stt16 init_timer //清内部TIMER计数器
if(i2c_start_flag) //启动I2C通讯处理后这个标志会被置1
{
I2C_SDA_INPUT
reset //系统复位
}
}
intrq = 0 //清中断标志
popaf //弹栈
reti //中断返回

//----------------------------------------
//input: ms
//用该函数可以再4M的频率下得到近似1毫秒的延时,在第一个内核中调用中断会导致延时加长
//----------------------------------------
/*delayXms:
while(Xms)
{
wdreset
ms_cnt = 20
while(ms_cnt)
{
delay 195
ms_cnt--
}
Xms--
}
ret*/

//用IO口模拟I2C slave模式的子函数
i2c_slave:
I2C_SDA_INPUT //将SDA设为输入
i2c_start:
//I2C空闲状态下SDA和SCL同为高电平,要启动I2C前初始状态必须是两者同为高
stt16 init_timer //清内部TIMER计数器
if(!I2C_SCL) //如果SCL为低,此时不用启动I2C通讯处理
{
goto i2c_stop
}
if(!I2C_SDA) //如果SDA为低,此时不用启动I2C通讯处理
{
goto i2c_stop
}

i2c_start_flag = 1 //启动I2C通讯处理,这个标志位会在定时中断中用到

//I2C的START信号是SDA和SCL同为高电平装态下SDA先变为低,然后SCL变为低
//判断I2C START信号
//等待SDA从高变低
stt16 init_timer //清内部TIMER计数器
wait0 I2C_SDA //应广特有的等待IO变低指令,等待SDA从高变低,如果长时间没有变低,会触发定时中断,系统复位
nop //加适当延时消除IO抖动的影响
nop
nop
nop
//等待SCL从高变低,原理同上
stt16 init_timer
wait0 I2C_SCL //if overtime MCU will auto reset
nop
nop
nop
nop

//已经判断为得到有效START信号


//开始接收I2C的器件地址,为了实现高速处理,程序顺序处理,没有使用循环处理方式
i2c_device = 0
stt16 init_timer //device bit7
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.7
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit6
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.6
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit5
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.5
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit4
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.4
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit3
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.3
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit2
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.2
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit1
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.1
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit0
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.0
}
wait0 I2C_SCL
//nop //后面的比较操作会耗费时间,可以不用延时
//nop
//nop
//nop


if(i2c_device == I2C_READ_CMD) //I2C进行读操作,同样为了实现高速处理,程序顺序处理,没有使用循环处理方式
{
//回复slave ACK信号
I2C_SDA_OUTPUT
I2C_SDA_LOW
stt16 init_timer
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop


stt16 init_timer //i2c_read_byte bit7
if(i2c_read_byte.7)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit6
if(i2c_read_byte.6)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit5
if(i2c_read_byte.5)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit4
if(i2c_read_byte.4)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit3
if(i2c_read_byte.3)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit2
if(i2c_read_byte.2)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit1
if(i2c_read_byte.1)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit0
if(i2c_read_byte.0)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop

I2C_SDA_INPUT
stt16 init_timer //master ack/nack
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //END
wait1 I2C_SCL
nop
nop
nop
nop
stt16 init_timer
wait1 I2C_SDA
nop
nop
nop
nop
}
else if(i2c_device == I2C_WRITE_CMD) //I2C是进行写操作,同样为了实现高速处理,程序顺序处理,没有使用循环处理方式
{
//slave ACK
I2C_SDA_OUTPUT //--------I2C SDA input/output switch----------
I2C_SDA_LOW
stt16 init_timer
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop

I2C_SDA_INPUT
i2c_write_byte = 0
stt16 init_timer //i2c_write_byte bit7
if(I2C_SDA)
{
set1 i2c_write_byte.7
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit6
if(I2C_SDA)
{
set1 i2c_write_byte.6
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit5
if(I2C_SDA)
{
set1 i2c_write_byte.5
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit4
if(I2C_SDA)
{
set1 i2c_write_byte.4
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit3
if(I2C_SDA)
{
set1 i2c_write_byte.3
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit2
if(I2C_SDA)
{
set1 i2c_write_byte.2
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit1
if(I2C_SDA)
{
set1 i2c_write_byte.1
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit0
if(I2C_SDA)
{
set1 i2c_write_byte.0
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop

//slave NACK
I2C_SDA_OUTPUT //--------I2C SDA input/output switch----------
I2C_SDA_HIGH
stt16 init_timer
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
I2C_SDA_INPUT //--------I2C SDA input/output switch----------
nop
nop
stt16 init_timer //END
wait1 I2C_SCL
nop
nop
nop
nop
stt16 init_timer
wait1 I2C_SDA
//nop
//nop
//nop
//nop

//下面代码用户可根据实际情况进行修改,这里是将I2C写入的数据取反后放到读操作位置
i2c_read_byte = ~i2c_write_byte

}

i2c_stop:
I2C_SDA_INPUT
i2c_start_flag = 0 //I2C stop work

ret

//----------------FPPA0-------------------
main0:


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

disgint
inten = 0

mov a,0b000_11_111 //disable timer
mov t16m,a

delay 200

clkmd.0 = 0 //pa.5 as GPIO

//注意IO口的输入输出设定
pa = 0b1111_1111
pac = 0b0000_0000
paph = 0b1111_1111
pb = 0b1111_1111
pbc = 0b0000_0000
pbph = 0b1111_1111


init_timer = 7768 //从7768进行校准为100ms
mov a,0b100_11_111
mov t16m,a
stt16 init_timer


delay 200

mov a,0
mov intrq,a

i2c_start_flag = 0 //I2C not start work


// adcdi = 0b0000_0100 //pb2 is analog input
// adcc = 0b10_0010_00 //enable ADC, select pb2
// adcm = 0b000_0100_0 //system clock/16
//adcm = 0b000_0111_0 //system clock/128
set1 fppen.1 //eanble FPPA1
clkmd.1 = 1 //enable watch dog
wdreset //clear watch dog

// Xms = 100
// call delayXms

stt16 init_timer
intrq = 0
inten.T16 = 1 //打开定时中断
engint


main0_loop:
init_timer = 0
wdreset
//用户可以在这里添加自己想要的任意代码,这里可以实现任意一个普通单片机能够是想的功能
goto main0_loop


//----------------FPPA1-------------------
main1:
sp = 0x38
main1_loop:
call i2c_slave
goto main1_loop

程序中的多个NOP可以用DELAY3代替,用DELAY 指令可以节省程序空间

I2C启动判断代码用下面部分更可靠(2012.12.22)

//wait SDA and SCL high at the same time
while((!I2C_SDA) || (!I2C_SCL))
{
stt16init_timer
nop
nop
nop
nop
}


if(!I2C_SDA)
{
gotoi2c_stop
}
if(!I2C_SCL)
{
gotoi2c_stop
}

代码已编译,未调试


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6078

    文章

    45589

    浏览量

    673916
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    探索S1C17F57:低功耗16位单片机的卓越之选

    仿真器)的16位单片机。其核心是16位CPU S1C17,集成了32K字节闪存、2K字节RAM、UART/SPI/I2C等串行接口、定时器
    的头像 发表于 03-31 09:15 194次阅读

    探索MAX7306:多功能I2C/SMBus接口GPIO与LED驱动器

    探索MAX7306/MAX7307:多功能I2C/SMBus接口GPIO与LED驱动器 在电子设计领域,对于高效、灵活的GPIO扩展和LED驱动方案的需求从未停止。今天,我们将深入探讨Maxim公司
    的头像 发表于 02-02 15:55 261次阅读

    CW32单片机I2C接口读写EEPROM芯片

    一、概述 CW32L083 内部集成 2I2C 控制器,能按照设定的传输速率(标准,快速,高速)将需要发送的数据按照 I2C 规范串行发送到
    发表于 01-12 08:20

    解锁NXP NTAG I2C plus:开启NFC应用新境界

    : NT3H2211W0FT1X.pdf 一、产品概述 NXP NTAG I2C plus系列连接式NFC标签,巧妙地将无源NFC接口与接触式I2C
    的头像 发表于 01-08 16:45 711次阅读

    I2C 为什么只要两根线就能搞定通信?

    到目前为止,我们已经讨论了SPI通信和UART通信的基础知识,现在让我们讨论本系列的最后一个协议,即集成电路间协议(I2C)。如果您曾经构建过使用OLED显示器、气压传感器或陀螺仪/加速度计模块
    的头像 发表于 01-04 09:14 2093次阅读
    <b class='flag-5'>I2C</b> 为什么只要两根线就能搞定通信?

    基于FPGA的I2C控制模块设计

    I2C_WRITE_WDATA.v模块实现I2C写时序,I2C_Controller (I2C控制器)例化了I2C_WRITE_WDATA.
    的头像 发表于 12-26 09:48 6112次阅读
    基于FPGA的<b class='flag-5'>I2C</b>控制模块设计

    NXP NTAG I2C plus:解锁NFC连接新可能

    NXP NTAG I2C plus:解锁NFC连接新可能 在当今的电子设备领域,NFC技术凭借其便捷性和高效性,在众多应用场景中得到了广泛应用。NXP推出的NTAG I2C plus系列产品,作为
    的头像 发表于 12-24 15:55 548次阅读

    AS32X601的I2C模块操作EEPROM详解

    国科安芯推出的AS32X601系列MCU芯片内置的I2C模块提供了符合工业标准的两线串行制接口,可用于MCU和外部I2C设备的通讯。I2C
    的头像 发表于 12-21 21:39 1655次阅读
    AS32X601的<b class='flag-5'>I2C</b>模块操作EEPROM详解

    CW32 I2C接口的主要特性

    CW32F030 内部集成 2I2C 控制器,能按照设定的传输速率(标准,快速,高速)将需要发送的数据按照 I2C规范串行发送到 I2C
    发表于 12-16 07:51

    CW32单片机I2C接口来读写EEPROM芯片

    一、概述 CW32L083 内部集成 2I2C 控制器,能按照设定的传输速率(标准,快速,高速)将需要发送的数据按照 I2C 规范串行发送到
    发表于 12-09 07:43

    深入剖析I2C协议

    I2C是由Philips开发的简单的双向两线总线,在深入浅出理解SPI协议中,我们区分了单工,半双工,全双工协议数据流向的区别,根据特征,I2C协议属于半双工协议(即同一时刻,数据单向流动)。此外
    的头像 发表于 08-21 15:10 3949次阅读
    深入剖析<b class='flag-5'>I2C</b>协议

    I2C总线通信,为什么要进行电气隔离?

    I2C总线采用双向二线制,支持多主机多从通信,具备高可靠性、抗干扰能力强,广泛应用于嵌入式系统中。
    的头像 发表于 08-11 11:04 2699次阅读
    <b class='flag-5'>I2C</b>总线通信,为什么要进行电气隔离?

    STM32有哪些MCU能支持I2C HS模式和同时支持I3C 的吗?

    如题,想请问下STM32有哪些产品,能支持I2C HS模式,速率3.4Mbit/s。同时又支持I3C的(SDR12.5M),现在有个外设 分别支持I2C HS slave,I3C SD
    发表于 08-04 06:06

    高效率、6通道、白光LED驱动器,带I2C接口 skyworksinc

    电子发烧友网为你提供()高效率、6通道、白光LED驱动器,带I2C接口相关产品参数、数据手册,更有高效率、6通道、白光LED驱动器,带I2C接口的引脚图、接线图、封装手册、中文资料、英
    发表于 07-30 18:31
    高效率、6通道、白光LED驱动器,带<b class='flag-5'>I2C</b><b class='flag-5'>接口</b> skyworksinc

    简单了解I2C接口

    在电子电路的复杂世界里,各种电路模块设备需要相互通信才能协同工作 ,I2C接口就像是电路模块设备间的沟通桥梁,今天就带大家深入了解它。
    的头像 发表于 05-08 14:15 2835次阅读
    简单了解<b class='flag-5'>I2C</b><b class='flag-5'>接口</b>