Chinaunix首页 | 论坛 | 博客
  • 博客访问: 133521
  • 博文数量: 55
  • 博客积分: 1870
  • 博客等级: 上尉
  • 技术积分: 540
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-21 20:51
文章分类

全部博文(55)

文章存档

2011年(27)

2009年(3)

2008年(25)

我的朋友

分类: C/C++

2011-05-04 13:28:20

声明:本文转载于http://www.cnblogs.com/kingst,版权归黑金动力社区(http://www.heijin.org)所有。

P1011818

 

简介 

      这一节,我们来讲一讲有关IIC总线的实验,在硬件中,我们实用了24LC04,一个512字节的EEPROM。在NIOS II中,没有集成IIC接口,为了实现这一功能,我们有两种途径,一种就是自己写IP核或者移植别人的IP核,另一种方法就是通过IO口模拟IIC总线协议。我们这一节采用的方法是后者,通过IO口模拟IIC总线协议,以达到对24LC04控制读写的目的。

      首先,我简单介绍一下IIC总线的原理,大家稍微了解一下。IIC(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率100kbps。它在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。

开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。

结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。

应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。

这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。下图就为IIC总线的时序图。

clip_image002

简单介绍之后,我们就要开始实践一下了,开始吧

硬件开发

      首先,需要在软核中添加两个IO模块,并将其命名为SCL和SDA,其中,SCL为output建ports only(仅输出),SDA为Bidirection (tristate) port(双向),建好以后,如下图所示

clip_image004

      接下来,我们自动分配一下地址,编译。

完成后,我们回到Quartus界面。然后我们来分配引脚,如下图所示

clip_image006

      分配好管脚以后,我们运行TCL脚本文件,开始编译(Ctrl+L)……

      编译完成后,我们的硬件部分就结束了,接下来,就是我们的软件开发部分了。

软件开发

      首先,我们打开NIOS II 9.0 IDE,然后进行编译(Ctrl+B)。

      编译好以后,我们看一下system.h文件,看是否多出了SCL和SDA部分代码。跟我们预期的一样,system.h文件中出现了SCL和SDA部分代码,如下表所示

01/*
02 * SCL configuration
03 *
04 */
05#define SCL_NAME "/dev/SCL"
06#define SCL_TYPE "altera_avalon_pio"
07#define SCL_BASE 0x00201060
08……
09/*
10 * SDA configuration
11 *
12 */
13 
14#define SDA_NAME "/dev/SDA"
15#define SDA_TYPE "altera_avalon_pio"
16#define SDA_BASE 0x00201070
17……

      在跟大家讨论过程中,我了解到很多人都想知道有关NIOS II自带的API的用法,所以,今天我就用这种方式来实现我们的程序。不过我还是推荐大家用我之前的方式编写程序,道理我已经说过了, 在此不再重复。

下面我们在inc目录下建立一个iic.h文件,如下表所示

01#ifndef IIC_H_
02#define IIC_H_
03 
04#define   OUT     1
05#define   IN      0
06 
07typedef struct{
08    void (* write_byte)(unsigned short addr, unsigned char dat);
09    unsigned char (* read_byte)(unsigned short addr);
10}IIC;
11 
12extern IIC iic;
13 
14#endif /*IIC_H_*/

接下来,我们需要在driver下建立iic.c文件,如下表所示

 

001#include
002#include
003#include
004 
005#include "system.h"
006#include "altera_avalon_pio_regs.h"
007#include "alt_types.h"
008#include "../inc/iic.h"
009 
010static alt_u8 read_byte(alt_u16 addr);
011static void write_byte(alt_u16 addr, alt_u8 dat);
012 
013IIC iic ={
014    .write_byte = write_byte,
015    .read_byte = read_byte
016};
017 
018 
019/*
020 * ===  FUNCTION  ===================================================
021 *         Name:  start
022 *  Description:  IIC启动
023 * =================================================================
024 */
025static void start(void)   
026{
027    IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE, OUT);
028    IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE, 1);
029    IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1);
030    usleep(10);
031    IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE, 0);
032    usleep(5);
033}
034/*
035 * ===  FUNCTION  ===================================================
036 *         Name:  uart_send_byte
037 *  Description:  IIC停止
038 * ==================================================================
039 */
040static void stop(void)    
041{
042    IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE, OUT);
043    IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE, 0);
044    IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0);
045    usleep(10);
046    IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1);
047    usleep(5);
048    IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE, 1);
049    usleep(10);
050}
051/*
052 * ===  FUNCTION  ===================================================
053 *         Name:  ack
054 *  Description:  IIC应答
055 * =================================================================
056 */
057static void ack(void)    
058{
059    alt_u8 tmp;
060     
061    IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0);
062    IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE, IN);
063    usleep(10);
064    IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1);
065    usleep(5);
066    tmp = IORD_ALTERA_AVALON_PIO_DATA(SDA_BASE);
067    usleep(5);
068    IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0);
069    usleep(10);
070     
071    while(tmp);
072}
073/*
074 * ===  FUNCTION  ===================================================
075 *         Name:  iic_write
076 *  Description:  IIC写一个字节
077 * =================================================================
078 */
079void iic_write(alt_u8 dat)   
080{
081    alt_u8 i, tmp;
082     
083    IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE, OUT);
084     
085    for(i=0; i<8; i++){
086        IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0);
087        usleep(5);
088        tmp = (dat & 0x80) ? 1 : 0;
089        dat <<= 1;
090        IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE, tmp);
091        usleep(5);
092        IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1);
093        usleep(10);
094    }
095}
096/*
097 * ===  FUNCTION  ===================================================
098 *         Name:  read
099 *  Description:  IIC读一个字节
100 * ==================================================================
101 */
102static alt_u8 iic_read(void)   
103{
104    alt_u8 i, dat = 0;
105     
106    IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE, IN);
107  
108    for(i=0; i<8; i++){
109        IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0);
110        usleep(10);
111        IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1);
112        usleep(5);
113        dat <<= 1;
114        dat |= IORD_ALTERA_AVALON_PIO_DATA(SDA_BASE);
115        usleep(5);
116    }
117   
118    usleep(5);
119    IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0);
120    usleep(10);
121    IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1);
122    usleep(10);
123    IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0);
124     
125    return dat;
126}
127 
128/*
129 * ===  FUNCTION  ===================================================
130 *         Name:  write_byte
131 *  Description:  向EEPROM写一个字节
132 * =================================================================
133 */
134static void write_byte(alt_u16 addr, alt_u8 dat)
135{
136    alt_u8 cmd;
137    cmd = (0xa0 | (addr >> 7)) & 0xfe;
138     
139    start();
140    iic_write(cmd);
141    ack();
142    iic_write(addr);
143    ack();
144    iic_write(dat);
145    ack();
146    stop();  
147}
148/*
149 * ===  FUNCTION  ===================================================
150 *         Name:  read_byte
151 *  Description:  从EEPROM读一个字节
152 * =================================================================
153 */
154static alt_u8 read_byte(alt_u16 addr)
155{
156    alt_u8 cmd, dat;
157    cmd = (0xa0 | (addr >> 7)) & 0xfe;
158     
159    start();
160    iic_write(cmd);
161    ack();
162    iic_write(addr);
163    ack();
164    start();
165    cmd |= 0x01;
166    start();
167    iic_write(cmd);
168    ack();
169    dat = iic_read();
170    stop();  
171     
172    return dat;
173}

最后,我们来建立main.c函数

01#include
02#include "../inc/iic.h"
03#include
04#include "alt_types.h"
05 
06alt_u8 write_buffer[512], read_buffer[512];
07 
08int main()
09{
10    alt_u16 i, err;
11    alt_u8 dat;
12 
13    printf("\nWriting data to EEPROM!\n");
14     
15    //写入512btye的数据,前256个数字为0到255,后256个数据为1
16    for(i=0; i<512; i++){
17        if(i<256)
18            dat = i;
19        else
20            dat = 1;
21             
22        iic.write_byte(i, dat);
23        write_buffer[i] = dat;
24        printf("0x%02x ", dat);
25        usleep(10000);
26    }
27   
28    printf("\nReading data from EEPROM!\n");
29     
30    //将512byte数据读出来并打印
31    for(i=0; i<512; i++){
32        read_buffer[i] = iic.read_byte(i);
33        printf("0x%02x ", read_buffer[i]);
34        usleep(1000);
35    } 
36   
37    err = 0;
38    printf("\nVerifing data!\n");
39     
40    //对比数据是否相同,如果有不同,说明读写过程有错误
41    for(i=0; i<512; i++){
42        if(read_buffer[i] != write_buffer[i])
43        err ++;
44    } 
45   
46    if(err == 0)
47        printf("\nData write and read successfully!\n");
48    else
49        printf("\nData write and read failed!--%d errors\n", err);
50     
51    return 0;
52}

      程序很简单,大家只要对IIC总线有一定的了解就会明白的。

      好的,这节的内容就讲到这,谢谢大家对我的支持。如果有问题,可以给我留言或者直接加入我们的NIOS技术高级群:100364900,也可以加我的qq:984597569

阅读(2002) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~