打印
[Cortex-M0技术交流]

【第7帖】I2C硬件程序实现

[复制链接]
2707|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nixianmin|  楼主 | 2011-11-13 07:35 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 nixianmin 于 2011-11-13 07:37 编辑

好久没发帖子了,前段时间学了下LOOK,现在又回来用库函数试试。参考坛里的I2C帖子写了个I2C,调试成功。刚开始看官方例子,无从下手,后来参考多了,才开始下手,无非就是在I2C的中断里通过status状态码判断,并根据参考手册上的I2C数据传输模式的图来判断。我这个程序就是实现简单的I2C操作,用中断断点来看读取的数据,写的有点不好,只是实现罢了。

main.c

/*********************************************
//
//
**********************************************/
#include<stdio.h>
#include"NUC1xx.h"
#include"M0Base.h"
#include"DrvGPIO.h"
#include"M0Uart.h"
#include"M0Timer.h"
#include"lcd1602.h"
#include"m0rtc.h"
#include"M0I2c.h"

int main(void)
{

  UNLOCKREG();   //解寄存器锁保护
  PLL50M();
  LOCKREG();
  i2c_tr_buf[0]='0';
  i2c_tr_buf[1]='1';
  i2c_tr_buf[2]='2';
  i2c_tr_buf[3]='3';
  i2c_tr_buf[4]='4';

  InitUart0();
  InitTimer0();
  InitLcd1602();
  InitRtc();
  InitI2c_Master();
  Set_I2c_Start(0xa0,I2C_WRITE,10,0x0000);
  Set_I2c_Start(0xa0,I2C_WRITE,0,0x0002);           //不写数据,只写存储地址,和读数据一起用
  Set_I2c_Start(0xa0,I2C_READ,5,0x00);//这里地址不起作用

  while(1)
  {
         
  }
}




m0i2c.h
/*********************************************
//
//
**********************************************/
#ifndef _M0I2C_H_
#define _M0I2C_H_

#define I2C_READ  1
#define I2C_WRITE  0

extern uint8_t i2c_tr_buf[],i2c_re_buf[];
extern uint8_t i2c_flag;

void InitI2c_Master(void);

void Set_I2c_Start(int8_t ssalve,int8_t srw,int8_t snum,int16_t sadd);

#endif




m0i2c.c
/*********************************************
//
//
**********************************************/
#include"stdio.h"
#include"NUC1xx.h"
#include"DrvI2C.H"
#include"DrvGPIO.H"
#include"DrvSYS.h"
#include"m0i2c.h"

uint8_t i2c_tr_buf[10]={0};
uint8_t        i2c_re_buf[10]={0};
uint8_t i2c_flag=0;

typedef struct{
        int8_t i2c_salve;        //传输从机地址
        int8_t i2c_rw;
        int8_t dat_num;                //传输数据个数
        int8_t dat_cnt;                //传输数据数据计数
        int16_t dat_add;   //传输数据的其实地址

}I2C_TYPE;

volatile I2C_TYPE i2c={0,0,0,0};
//地址对读数据无效
//读数据只能先写地址,再读数据
void Set_I2c_Start(int8_t ssalve,int8_t srw,int8_t snum,int16_t sadd)
{
        uint16_t cnt=0;
        i2c.i2c_salve=ssalve;
        i2c.i2c_rw=srw;
        i2c.dat_num=snum;
        i2c.dat_cnt=0;
        i2c.dat_add=sadd;
        i2c_flag=0 ;

        DrvI2C_Ctrl(I2C_PORT1, 1, 0, 0, 0);
        while((i2c_flag!=1)&&(cnt!=0xffff))
                cnt++;//判断是否读取或写结束
        DrvSYS_Delay(8000);//延时
}

void I2c1CallBack(uint32_t status)
{
        if(i2c.i2c_rw==I2C_READ)  //读状态
        {
                if (status == 0x08)                     /* START has been transmitted and prepare SLA+W */
            {
                DrvI2C_WriteData(I2C_PORT1, (i2c.i2c_salve|0x01));         //读地址数据
                DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0);
            }  
            else if (status == 0x40)                /* SLA+R has been transmitted and ACK has been received */
            {
                DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1);          //have ack
            }      
                else if(status==0x50)
                {
                         i2c_re_buf[i2c.dat_cnt++] = DrvI2C_ReadData(I2C_PORT1);
                        if(i2c.dat_cnt<(i2c.dat_num-1))
                        {
                        DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 1);
                        }
                        else
                        {
                                DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0);
                        }
               
                }
            else if (status == 0x58)                /* DATA has been received and NACK has been returned */
            {
                i2c_re_buf[i2c.dat_cnt++] = DrvI2C_ReadData(I2C_PORT1);
                DrvI2C_Ctrl(I2C_PORT1, 0, 1, 1, 0);
                        i2c_flag=1;
            }
            else
            {
                printf("Status 0x%x is NOT processed\n", status);
            }  
       
        }
        else if(i2c.i2c_rw==I2C_WRITE)   //写状态
        {
                if (status == 0x08)                     /* START has been transmitted */
            {
                DrvI2C_WriteData(I2C_PORT1, (i2c.i2c_salve&0xfe));         //读地址数据
                DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0);
            }   
            else if (status == 0x18)                /* SLA+W has been transmitted and ACK has been received */
            {
                DrvI2C_WriteData(I2C_PORT1, (int8_t)(i2c.dat_add));         //传输高位地址
                        i2c.dat_cnt++;
                DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0);
            }
            else if (status == 0x20)                /* SLA+W has been transmitted and NACK has been received */
            {
                
                DrvI2C_Ctrl(I2C_PORT1, 1, 1, 1, 0);
            }   
            else if (status == 0x28)                /* DATA has been transmitted and ACK has been received */
            {
                if (i2c.dat_cnt<2)
                {
                    DrvI2C_WriteData(I2C_PORT1, (int8_t)(i2c.dat_add>>8));//传输低位地址
                                i2c.dat_cnt++;
                    DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0);
                }
                        else if(i2c.dat_cnt<(i2c.dat_num+2))
                        {
                                 DrvI2C_WriteData(I2C_PORT1, i2c_tr_buf[i2c.dat_cnt-2]);
                                i2c.dat_cnt++;
                    DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0);
                        }
                else
                {
                    DrvI2C_Ctrl(I2C_PORT1, 0, 1, 1, 0);//send a stop
                                i2c_flag=1;
                }        
            }
            else
            {
                printf("Status 0x%x is NOT processed\n", status);
            }
       
        }
}

void InitI2c_Master()
{
        DrvGPIO_InitFunction(E_FUNC_I2C1);
        DrvI2C_Open(I2C_PORT1, 50000);
        DrvI2C_EnableInt(I2C_PORT1);
        DrvI2C_InstallCallback(I2C_PORT1, I2CFUNC, I2c1CallBack);
}

I2C.rar

1.38 MB

相关帖子

沙发
hotpower| | 2011-11-13 09:27 | 只看该作者
库函数的套路就是先初始化设置并安装回调函数。然后启动硬件开始。在回调函数处理或设置标志在主循环中处理。iic接线简单,但比spi要复杂些。

使用特权

评论回复
板凳
nixianmin|  楼主 | 2011-11-13 12:15 | 只看该作者
2# hotpower 如果只控制些I2C总线的器件,用模拟方式比较简单,
硬件的麻烦,我以前写430用硬件愣是没搞出来,只好用模拟方式

使用特权

评论回复
地板
hotpower| | 2011-11-13 12:23 | 只看该作者
晕,模拟要占用大量的时间资源

使用特权

评论回复
5
chy117| | 2011-11-13 22:09 | 只看该作者
MARK

使用特权

评论回复
6
yuandm1| | 2011-11-13 22:18 | 只看该作者
继续学习

使用特权

评论回复
7
xinxi| | 2011-11-13 23:30 | 只看该作者
占用2个中断,88条指令汇编实现i2c从模式,100k 速度,不怎么占用系统资源,因为中断处理时间 很短 很短,没有长时间独占cpu,,,如果搞成 一检测到开始标志,cpu就全部用来接收i2c数据,其它事情不能做,一直到检测到结束标志或者出错才释放cpu占用,那就没意思了哦

使用特权

评论回复
8
hotpower| | 2011-11-14 09:59 | 只看该作者
回调函数类似与事件或消息驱动机制。
当中断来后,在中断中先查看用户回调是否安装。
即回调函数指针是否为空。非空即有用户回调,
要特别注意此回调函数实际还是运行在中断服务程序之中的,不要处理过长时间。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:电机控制,TI InstaSpin Foc交流群:335663930

40

主题

431

帖子

6

粉丝