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
}

代码已编译,未调试


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

    关注

    5999

    文章

    43966

    浏览量

    620734
收藏 人收藏

    评论

    相关推荐

    使用两片ADU360进行I2C通信,当与从进行通信时,从无法进入I2C中断是为什么?

    问题说明:使用两片ADU360进行I2C通信,主机使用IO口模拟方式,从使用内部外设 主机IO口模拟方式,确认是可行,当与从进行通信时,从无法进入
    发表于 01-15 06:47

    LTC2471的I2C接口没有ACK应答是怎么回事?

    LTC2471的接口部分如图所示: 其中SCL和SDA直接与PIC16F1947单片机I2C接口的SCL和SDA相连。VDD电压5V。 用示波器测量SDA和SCL的波形如下: 可
    发表于 01-05 11:44

    ADXL345运行时间长了i2c通讯不上怎么解决?

    stm32单片机通过i2c接口实时读取adxl345的三轴加速度数据,发现刚上电的时候正常工作。运行一段时间,大概几小时,i2c通讯失败。 单片机
    发表于 01-01 08:20

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

    CW32单片机I2C接口读写EEPROM芯片介绍
    的头像 发表于 11-09 17:42 585次阅读
    CW32<b class='flag-5'>单片机</b><b class='flag-5'>I2C</b><b class='flag-5'>接口</b>读写EEPROM芯片介绍

    51单片机能不能io模拟i2c

    51单片机能不能io模拟i2c,两个单片机之间通讯,主机可以模拟,从没有写过,有没有例程
    发表于 11-02 07:00

    AT32F423 I2C使用指南

    AT32 的 I2C 总线接口用于处理微控制器和串行 I2C 总线之间的通信,支持主机和从模式,支持唤醒深睡眠模式,最大通信速度为 1Mbit/s(增强快速模式 fast mode
    发表于 10-26 06:33

    lpc1114如何设置监控i2c数据?

    有一条正常通讯的i2c总线,想截取通讯内容,看手册好像是可以用lpc1114监听,然后想用串口输出数据,那么单片机i2c需要怎么配置
    发表于 09-27 07:07

    全面掌握面试必考题I2C协议 - 第12节

    I2C协议
    充八万
    发布于 :2023年09月01日 19:07:43

    80 第23.1讲 I2C实验-I2C协议和6U的I2C控制器详解 - 第2

    程序代码I2C协议
    充八万
    发布于 :2023年08月17日 10:03:33

    基于 FPGA 的模拟 I2C协议系统设计

    今天给大侠带来基于FPGA的 模拟 I2C 协议设计,由于篇幅较长,分三篇。今天带来第一篇,上篇, I2C 总线解析以及模拟 I2C 接口程序的基本框架。话不多说,上货。 这里也给出后
    发表于 08-14 18:21

    如何驱动I2C接口的OLED屏?

    前面我们介绍了驱动SPI接口LCD5110显示屏的方法,这次介绍一下如何驱动I2C接口的OLED屏,该OLED屏为0.91寸单色屏。
    发表于 06-27 06:37

    89c51单片机模拟i2c总线怎么实现一主多从呢?

    i2c总线上,连接多个89C51,把一个89C51做为主控器,其他的作为被控器,能否实现一个单片机控制多个单片机的功能,如果能,该如何实现
    发表于 05-08 18:05

    STC单片机模拟的I2C总线上数据传送速率能达到12M吗?

    STC单片机模拟的I2C总线上数据传送速率能达到12M吗?
    发表于 05-08 17:44

    NodeMCU中的I2C接口是否可以高速运行?

    其发送到数据收集器 (RaspberryPi)。 对我来说,在一秒钟内实现尽可能多的计算量非常重要,因为用于后续处理的所获得数据的质量取决于它。 HMC5983 支持标准、快速和高速模式下的 I2C 接口
    发表于 04-27 08:24