声明:本文转载于http://www.cnblogs.com/kingst,版权归黑金动力社区(http://www.heijin.org)所有。
简介 这一节,我们来讲一讲有关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总线的时序图。
简单介绍之后,我们就要开始实践一下了,开始吧
硬件开发 首先,需要在软核中添加两个IO模块,并将其命名为SCL和SDA,其中,SCL为output建ports only(仅输出),SDA为Bidirection (tristate) port(双向),建好以后,如下图所示
接下来,我们自动分配一下地址,编译。
完成后,我们回到Quartus界面。然后我们来分配引脚,如下图所示
分配好管脚以后,我们运行TCL脚本文件,开始编译(Ctrl+L)……
编译完成后,我们的硬件部分就结束了,接下来,就是我们的软件开发部分了。
软件开发 首先,我们打开NIOS II 9.0 IDE,然后进行编译(Ctrl+B)。
编译好以后,我们看一下system.h文件,看是否多出了SCL和SDA部分代码。跟我们预期的一样,system.h文件中出现了SCL和SDA部分代码,如下表所示
05 | #define SCL_NAME "/dev/SCL" |
06 | #define SCL_TYPE "altera_avalon_pio" |
07 | #define SCL_BASE 0x00201060 |
14 | #define SDA_NAME "/dev/SDA" |
15 | #define SDA_TYPE "altera_avalon_pio" |
16 | #define SDA_BASE 0x00201070 |
在跟大家讨论过程中,我了解到很多人都想知道有关NIOS II自带的API的用法,所以,今天我就用这种方式来实现我们的程序。不过我还是推荐大家用我之前的方式编写程序,道理我已经说过了, 在此不再重复。
下面我们在inc目录下建立一个iic.h文件,如下表所示
08 | void (* write_byte)(unsigned short addr, unsigned char dat); |
09 | unsigned char (* read_byte)(unsigned short addr); |
接下来,我们需要在driver下建立iic.c文件,如下表所示
006 | #include "altera_avalon_pio_regs.h" |
007 | #include "alt_types.h" |
008 | #include "../inc/iic.h" |
010 | static alt_u8 read_byte(alt_u16 addr); |
011 | static void write_byte(alt_u16 addr, alt_u8 dat); |
014 | .write_byte = write_byte, |
015 | .read_byte = read_byte |
020 | * === FUNCTION =================================================== |
023 | * ================================================================= |
025 | static void start(void) |
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); |
031 | IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE, 0); |
035 | * === FUNCTION =================================================== |
036 | * Name: uart_send_byte |
038 | * ================================================================== |
040 | static void stop(void) |
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); |
046 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1); |
048 | IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE, 1); |
052 | * === FUNCTION =================================================== |
055 | * ================================================================= |
061 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0); |
062 | IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE, IN); |
064 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1); |
066 | tmp = IORD_ALTERA_AVALON_PIO_DATA(SDA_BASE); |
068 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0); |
074 | * === FUNCTION =================================================== |
076 | * Description: IIC写一个字节 |
077 | * ================================================================= |
079 | void iic_write(alt_u8 dat) |
083 | IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE, OUT); |
086 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0); |
088 | tmp = (dat & 0x80) ? 1 : 0; |
090 | IOWR_ALTERA_AVALON_PIO_DATA(SDA_BASE, tmp); |
092 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1); |
097 | * === FUNCTION =================================================== |
099 | * Description: IIC读一个字节 |
100 | * ================================================================== |
102 | static alt_u8 iic_read(void) |
106 | IOWR_ALTERA_AVALON_PIO_DIRECTION(SDA_BASE, IN); |
109 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0); |
111 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1); |
114 | dat |= IORD_ALTERA_AVALON_PIO_DATA(SDA_BASE); |
119 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0); |
121 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 1); |
123 | IOWR_ALTERA_AVALON_PIO_DATA(SCL_BASE, 0); |
129 | * === FUNCTION =================================================== |
131 | * Description: 向EEPROM写一个字节 |
132 | * ================================================================= |
134 | static void write_byte(alt_u16 addr, alt_u8 dat) |
137 | cmd = (0xa0 | (addr >> 7)) & 0xfe; |
149 | * === FUNCTION =================================================== |
151 | * Description: 从EEPROM读一个字节 |
152 | * ================================================================= |
154 | static alt_u8 read_byte(alt_u16 addr) |
157 | cmd = (0xa0 | (addr >> 7)) & 0xfe; |
最后,我们来建立main.c函数
02 | #include "../inc/iic.h" |
06 | alt_u8 write_buffer[512], read_buffer[512]; |
13 | printf("\nWriting data to EEPROM!\n"); |
15 | //写入512btye的数据,前256个数字为0到255,后256个数据为1 |
22 | iic.write_byte(i, dat); |
23 | write_buffer[i] = dat; |
24 | printf("0x%02x ", dat); |
28 | printf("\nReading data from EEPROM!\n"); |
32 | read_buffer[i] = iic.read_byte(i); |
33 | printf("0x%02x ", read_buffer[i]); |
38 | printf("\nVerifing data!\n"); |
40 | //对比数据是否相同,如果有不同,说明读写过程有错误 |
42 | if(read_buffer[i] != write_buffer[i]) |
47 | printf("\nData write and read successfully!\n"); |
49 | printf("\nData write and read failed!--%d errors\n", err); |
程序很简单,大家只要对IIC总线有一定的了解就会明白的。
好的,这节的内容就讲到这,谢谢大家对我的支持。如果有问题,可以给我留言或者直接加入我们的NIOS技术高级群:100364900,也可以加我的qq:984597569
阅读(2002) | 评论(0) | 转发(0) |