【龙芯1c库】封装模拟I2C接口和使用示例
2017-06-12 11:51
405 查看
龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库。Git地址:http://git.oschina.NET/caogos/OpenLoongsonLib1c
I2C接口是常用的接口之一,很多传感器都是使用I2C接口,本文使用普通GPIO模拟I2C,实现与温湿度传感器AM2320正常通信。 先展示如何使用模拟I2C接口,然后再来看看怎么封装这些接口的。
龙芯1c库中模拟I2C接口使用示例
系统初始化时,首先调用simulate_i2c_init()对gpio初始化,然后调用simulate_i2c_start()发送I2C的开始信号,发送开始信号之后,一般需要调用simulate_i2c_write_byte()发送I2C子设备地址,然后才是调用simulate_i2c_write_byte()或simulate_i2c_read_byte()收发数据,每一个字节的数据后面都有一个ACK或NACK信号(发送地址时也有ack信号),根据情况调用simulate_i2c_send_ack(),simulate_i2c_send_no_ack()或者simulate_i2c_read_ack(),最后调用simulate_i2c_stop()发送停止信号,结束一次I2C通信过程。
为啥每个函数都有个相同的入参“simulate_i2c_t *i2c_info”呢?目的是告诉每个函数模拟I2C的GPIO引脚和I2C时钟周期,这样可以实现一个程序中同时支持多个不同的模拟I2C接口,接多个传感器。理论上GPIO越多,同时支持模拟I2C的个数就越多。
本文通过温湿度传感器AM2320来测试模拟的I2C接口,可以根据需要随意选取普通GPIO连接AM2320的SCL和SDA引脚。只是需要注意所选引脚是否接有其它元器件。
VDD ------------------ 3.3V
GND ------------------ GND
SCL ------------------ GPIO57
SDA ------------------ GPIO56
这里是用GPIO模拟的I2C,理论上所有GPIO都可以用作SCL和SDA。另外AM2320的芯片手册中推荐SCL和SDA接上拉电阻,实测不接也是可以的。
代码很简单,调用函数test_simulate_i2c_am2320()读取一次温湿度信息,间隔3s读一次。读取一次温湿度信息需要先唤醒AM2320,然后发送读指令,最后才读温湿度数据。
这是获取一次温湿度信息的时序图。首先是唤醒AM2320,延时,再发送读温湿度的命令,延时,最后才是读取温湿度值。把波形放大后,如下
唤醒AM2320的时序,开始信号后,发送地址0xB8,然后延时1ms,再发结束信号
读命令的时序。开始信号,发地址0xB8,发发功能码0x3,发起始地址0x0,发寄存器长度0x4,结束信号
把读取温湿度信息的时序分为两个图,这样看得更清楚一些。
时序为:开始信号,发送地址,延时50us后,读取8字节的数据(其中包括温度,湿度和CRC),最后发送结束信号。
最后来看下串口打印信息
程序写好后,上电运行,对照芯片手册的时序图,接上示波器一看就知道对不对,哪里延时时间长了,哪里又短了,找着芯片手册中的时序图修改,直到满意为止。
只是在使用这些接口时,要仔细看芯片手册,改读I2C时,不要写I2C。假设发送地址后,需要连续读n个数据,如果在发生地址后,多写了一个数据后,再读I2C时,可能读到的是全0xff,并且没有ack。那是因为通信的对方已经放弃本次I2C通信,I2C变成空闲状态(SCL=1,SDA=1),所以读到的是0xff,并且没有ack。
完整的代码请到git查看,谢谢欣赏。
I2C接口是常用的接口之一,很多传感器都是使用I2C接口,本文使用普通GPIO模拟I2C,实现与温湿度传感器AM2320正常通信。 先展示如何使用模拟I2C接口,然后再来看看怎么封装这些接口的。
龙芯1c库中模拟I2C接口使用示例
模拟I2C接口简介
先来看看封装了那些接口,如下// 模拟i2c的接口信息 typedef struct { unsigned int scl_gpio; // SCL所在gpio引脚 unsigned int sda_gpio; // SDA所在gpio引脚 int delay_time; // 周期的1/2,单位us }simulate_i2c_t; /* * 模拟i2c初始化 * @i2c_info i2c的接口信息 */ void simulate_i2c_init(simulate_i2c_t *i2c_info); /* * 模拟I2C的开始 * @i2c_info i2c接口信息 */ void simulate_i2c_start(simulate_i2c_t *i2c_info); /* * 模拟I2C的停止 * @i2c_info i2c接口信息 */ void simulate_i2c_stop(simulate_i2c_t *i2c_info); /* * 给从设备发送一个ack应答信号 * @i2c_info i2c接口信息 */ void simulate_i2c_send_ack(simulate_i2c_t *i2c_info); /* * 给从设备发送一个no ack非应答信号 * @i2c_info i2c接口信息 */ void simulate_i2c_send_no_ack(simulate_i2c_t *i2c_info); /* * 读取从设备的ack应答信号 * @i2c_info i2c接口信息 * @ret 读取到的信号。0表示应答,1表示非应答 */ unsigned int simulate_i2c_read_ack(simulate_i2c_t *i2c_info); /* * 主设备从从设备那里读取一个8bit数据 * @i2c_info i2c接口信息 * @ret 读取的数据 */ unsigned char simulate_i2c_read_byte(simulate_i2c_t *i2c_info); /* * 主设备写8bit数据到从设备 * @i2c_info i2c接口信息 * @data 待写数据 */ void simulate_i2c_write_byte(simulate_i2c_t *i2c_info, unsigned char data);
系统初始化时,首先调用simulate_i2c_init()对gpio初始化,然后调用simulate_i2c_start()发送I2C的开始信号,发送开始信号之后,一般需要调用simulate_i2c_write_byte()发送I2C子设备地址,然后才是调用simulate_i2c_write_byte()或simulate_i2c_read_byte()收发数据,每一个字节的数据后面都有一个ACK或NACK信号(发送地址时也有ack信号),根据情况调用simulate_i2c_send_ack(),simulate_i2c_send_no_ack()或者simulate_i2c_read_ack(),最后调用simulate_i2c_stop()发送停止信号,结束一次I2C通信过程。
为啥每个函数都有个相同的入参“simulate_i2c_t *i2c_info”呢?目的是告诉每个函数模拟I2C的GPIO引脚和I2C时钟周期,这样可以实现一个程序中同时支持多个不同的模拟I2C接口,接多个传感器。理论上GPIO越多,同时支持模拟I2C的个数就越多。
本文通过温湿度传感器AM2320来测试模拟的I2C接口,可以根据需要随意选取普通GPIO连接AM2320的SCL和SDA引脚。只是需要注意所选引脚是否接有其它元器件。
用温湿度传感器AM2320测试模拟I2C接口
实物图
温湿度传感器AM2320占用的引脚VDD ------------------ 3.3V
GND ------------------ GND
SCL ------------------ GPIO57
SDA ------------------ GPIO56
这里是用GPIO模拟的I2C,理论上所有GPIO都可以用作SCL和SDA。另外AM2320的芯片手册中推荐SCL和SDA接上拉电阻,实测不接也是可以的。
代码清单
main.c
#include "../lib/public.h" #include "../lib/gpio.h" #include "../lib/delay.h" #include "../example/test_gpio.h" #include "../example/test_pwm.h" #include "../example/test_delay.h" #include "../example/test_simulate_i2c.h" // pmon提供的打印接口 struct callvectors *callvec; int main(int argc, char **argv, char **env, struct callvectors *cv) { callvec = cv; // -------------------------测试gpio---------------------- /* * 测试库中gpio作为输出时的相关接口 * led闪烁10次 */ // test_gpio_output(); /* * 测试库中gpio作为输入时的相关接口 * 按键按下时,指示灯点亮,否则,熄灭 */ // test_gpio_input(); // ------------------------测试PWM-------------------------------- // 测试硬件pwm产生连续的pwm波形 // test_pwm_normal(); // 测试硬件pwm产生pwm脉冲 // test_pwm_pulse(); /* * 测试gpio04复用为pwm,gpio06作为普通gpio使用 * PWM0的默认引脚位GPIO06,但也可以复用为GPIO04 * 当gpio06还是保持默认为pwm时,复用gpio04为pwm0,那么会同时在两个引脚输出相同的pwm波形 * 本函数旨在证明可以在gpio04复用为pwm0时,还可以将(默认作为pwm0的)gpio06作为普通gpio使用 */ // test_pwm_gpio04_gpio06(); // 测试pwm最大周期 // test_pwm_max_period(); // ------------------------测试软件延时-------------------------------- // 测试延时函数delay_1ms() // test_delay_1ms(); // 测试延时函数delay_1us() // test_delay_1us(); // 测试延时函数delay_1s() // test_delay_1s(); // ------------------------测试模拟I2C------------------------------ test_simulate_i2c_am2320(); return(0); }
test_simulate_i2c.c
// 测试模拟i2c #include "../lib/public.h" #include "../lib/delay.h" #include "../lib/simulate_i2c.h" // 接收缓存大小 #define RECV_BUFF_SIZE (8) // 读取的消息中每字节的含义 enum { AM2320_RSP_FUNC_ID = 0, // 功能码 AM2320_RSP_LEN, // 数据长度 AM2320_RSP_HUMI_HIGH, // 湿度高位 AM2320_RSP_HUMI_LOW, // 湿度低位 AM2320_RSP_TEMP_HIGH, // 温度高位 AM2320_RSP_TEMP_LOW, // 温度低位 AM2320_RSP_CRC_LOW, // CRC低位 AM2320_RSP_CRC_HIGH, // CRC高位 }; // 温湿度传感器AM2320的引脚接线信息 simulate_i2c_t am2320_info = { 57, 56, 10 }; // SCL=gpio57, SDA=gpio56, delay_time=10us // 温湿度传感器AM2320初始化 void am2320_init(void) { // 模拟i2c初始化 simulate_i2c_init(&am2320_info); return ; } /* * 计算crc * @ptr 待计算crc的数据的首地址 * @len 数据长度 */ unsigned short am2320_crc16(unsigned char *ptr, unsigned char len) { unsigned short crc = 0xFFFF; unsigned char i; while (len--) { crc ^= *ptr++; for (i=0; i<8; i++) { if (crc & 0x01) { crc >>= 1; crc ^= 0xA001; } else { crc >>= 1; } } } return crc; } // 从AM2320读取温湿度信息 void am2320_get_temp_humi(void) { const unsigned char addr = 0xB8; unsigned char recv_buff[RECV_BUFF_SIZE] = {0}; unsigned short recved_crc, calced_crc; int temp, humi; int i; // 唤醒AM2320 simulate_i2c_start(&am2320_info); simulate_i2c_write_byte(&am2320_info, addr); simulate_i2c_read_ack(&am2320_info); delay_ms(1); simulate_i2c_stop(&am2320_info); // 发送读指令 simulate_i2c_start(&am2320_info); simulate_i2c_write_byte(&am2320_info, addr); simulate_i2c_read_ack(&am2320_info); simulate_i2c_write_byte(&am2320_info, 0x03); simulate_i2c_read_ack(&am2320_info); simulate_i2c_write_byte(&am2320_info, 0x00); simulate_i2c_read_ack(&am2320_info); simulate_i2c_write_byte(&am2320_info, 0x04); simulate_i2c_read_ack(&am2320_info); simulate_i2c_stop(&am2320_info); // 读回数据 delay_ms(2); simulate_i2c_start(&am2320_info); simulate_i2c_write_byte(&am2320_info, addr | 0x01); simulate_i2c_read_ack(&am2320_info); delay_us(50); for (i=0; i<RECV_BUFF_SIZE; i++) { recv_buff[i] = simulate_i2c_read_byte(&am2320_info); simulate_i2c_send_ack(&am2320_info); } simulate_i2c_stop(&am2320_info); recved_crc = (recv_buff[AM2320_RSP_CRC_HIGH] << 8) + recv_buff[AM2320_RSP_CRC_LOW]; calced_crc = am2320_crc16(recv_buff, 6); if (recved_crc != calced_crc) { myprintf("[%s] crc error! recved_crc=0x%x, calced_crc=0x%x\n", __FUNCTION__, recved_crc, calced_crc); myprintf("[%s] recved data: func_id=%d, len=%d, humi[1]=0x%x, humi[0]=0x%x, temp[1]=0x%x, temp[0]=0x%x, crc[0]=0x%x, crc[1]=0x%x\n", __FUNCTION__, recv_buff[AM2320_RSP_FUNC_ID], recv_buff[AM2320_RSP_LEN], recv_buff[AM2320_RSP_HUMI_HIGH], recv_buff[AM2320_RSP_HUMI_LOW], recv_buff[AM2320_RSP_TEMP_HIGH], recv_buff[AM2320_RSP_TEMP_LOW], recv_buff[AM2320_RSP_CRC_LOW], recv_buff[AM2320_RSP_CRC_HIGH]); return ; } humi = (recv_buff[AM2320_RSP_HUMI_HIGH] * 0xff + recv_buff[AM2320_RSP_HUMI_LOW]) / 10; temp = (recv_buff[AM2320_RSP_TEMP_HIGH] * 0xff + recv_buff[AM2320_RSP_TEMP_LOW]) / 10; myprintf("[%s] humi=%d, temp=%d\n", __FUNCTION__, humi, temp); return ; } // 用模拟i2c接口与温湿度传感器AM2320通信,读取温湿度信息 void test_simulate_i2c_am2320(void) { // 温湿度传感器AM2320初始化 am2320_init(); while (1) { // 从AM2320读取温湿度信息 am2320_get_temp_humi(); // 等待3s delay_s(3); } }
test_simulate_i2c.h
// 测试模拟i2c #ifndef __OPENLOONGSON_TEST_SIMULATE_I2C_H #define __OPENLOONGSON_TEST_SIMULATE_I2C_H // 用模拟i2c接口与温湿度传感器AM2320通信,读取温湿度信息 void test_simulate_i2c_am2320(void); #endif
代码很简单,调用函数test_simulate_i2c_am2320()读取一次温湿度信息,间隔3s读一次。读取一次温湿度信息需要先唤醒AM2320,然后发送读指令,最后才读温湿度数据。
测试效果
这是获取一次温湿度信息的时序图。首先是唤醒AM2320,延时,再发送读温湿度的命令,延时,最后才是读取温湿度值。把波形放大后,如下
唤醒AM2320的时序,开始信号后,发送地址0xB8,然后延时1ms,再发结束信号
读命令的时序。开始信号,发地址0xB8,发发功能码0x3,发起始地址0x0,发寄存器长度0x4,结束信号
把读取温湿度信息的时序分为两个图,这样看得更清楚一些。
时序为:开始信号,发送地址,延时50us后,读取8字节的数据(其中包括温度,湿度和CRC),最后发送结束信号。
最后来看下串口打印信息
封装模拟I2C接口
接口要点
模拟I2C其实不难,就是根据I2C协议的时序,将普通GPIO拉低拉高,然后延时,再拉低拉高,再延时,再拉低拉高……程序写好后,上电运行,对照芯片手册的时序图,接上示波器一看就知道对不对,哪里延时时间长了,哪里又短了,找着芯片手册中的时序图修改,直到满意为止。
只是在使用这些接口时,要仔细看芯片手册,改读I2C时,不要写I2C。假设发送地址后,需要连续读n个数据,如果在发生地址后,多写了一个数据后,再读I2C时,可能读到的是全0xff,并且没有ack。那是因为通信的对方已经放弃本次I2C通信,I2C变成空闲状态(SCL=1,SDA=1),所以读到的是0xff,并且没有ack。
代码清单
simulate_i2c.c
// 模拟i2c的源文件 #include "public.h" #include "gpio.h" #include "delay.h" #include "simulate_i2c.h" /* * 配置SCL所在gpio引脚为输出模式 * @i2c_info i2c接口信息 */ void simulate_i2c_config_scl_out(simulate_i2c_t *i2c_info) { gpio_init(i2c_info->scl_gpio, gpio_mode_output); return ; } /* * 配置SDA所在gpio引脚为输出模式 * @i2c_info i2c接口信息 */ void simulate_i2c_config_sda_out(simulate_i2c_t *i2c_info) { gpio_init(i2c_info->sda_gpio, gpio_mode_output); return ; } /* * 配置SDA所在gpio引脚为输入模式 * @i2c_info i2c接口信息 */ void simulate_i2c_config_sda_in(simulate_i2c_t *i2c_info) { gpio_init(i2c_info->sda_gpio, gpio_mode_input); return ; } /* * SCL引脚输出高电平 * @i2c_info i2c接口信息 */ void simulate_i2c_scl_out_high(simulate_i2c_t *i2c_info) { gpio_set(i2c_info->scl_gpio, gpio_level_high); return ; } /* * SCL引脚输出低电平 * @i2c_info i2c接口信息 */ void simulate_i2c_scl_out_low(simulate_i2c_t *i2c_info) { gpio_set(i2c_info->scl_gpio, gpio_level_low); return ; } /* * SDA引脚输出高电平 * @i2c_info i2c接口信息 */ void simulate_i2c_sda_out_high(simulate_i2c_t *i2c_info) { gpio_set(i2c_info->sda_gpio, gpio_level_high); return ; } /* * SDA引脚输出低电平 * @i2c_info i2c接口信息 */ void simulate_i2c_sda_out_low(simulate_i2c_t *i2c_info) { gpio_set(i2c_info->sda_gpio, gpio_level_low); return ; } /* * 读取SDA引脚 * @i2c_info i2c接口信息 * @ret SDA引脚的电平值 */ unsigned int simulate_i2c_sda_in(simulate_i2c_t *i2c_info) { return gpio_get(i2c_info->sda_gpio); } /* * 模拟i2c初始化 * @i2c_info i2c的接口信息 */ void simulate_i2c_init(simulate_i2c_t *i2c_info) { // SCL输出高电平 simulate_i2c_config_scl_out(i2c_info); simulate_i2c_scl_out_high(i2c_info); return ; } /* * 模拟I2C的开始 * @i2c_info i2c接口信息 */ void simulate_i2c_start(simulate_i2c_t *i2c_info) { // SDA输出模式 simulate_i2c_config_sda_out(i2c_info); // 这里可能需要一个stop simulate_i2c_scl_out_high(i2c_info); delay_us(i2c_info->delay_time); simulate_i2c_sda_out_high(i2c_info); delay_us(2 * i2c_info->delay_time); // start simulate_i2c_sda_out_low(i2c_info); delay_us(i2c_info->delay_time); simulate_i2c_scl_out_low(i2c_info); delay_us(i2c_info->delay_time); return ; } /* * 模拟I2C的停止 * @i2c_info i2c接口信息 */ void simulate_i2c_stop(simulate_i2c_t *i2c_info) { // SDA输出模式 simulate_i2c_config_sda_out(i2c_info); // 先把SCL和SDA拉低 simulate_i2c_scl_out_low(i2c_info); delay_us(i2c_info->delay_time); simulate_i2c_sda_out_low(i2c_info); delay_us(i2c_info->delay_time); // stop simulate_i2c_scl_out_high(i2c_info); delay_us(i2c_info->delay_time); simulate_i2c_sda_out_high(i2c_info); delay_us(2 * i2c_info->delay_time); return ; } /* * 给从设备发送一个ack应答信号 * @i2c_info i2c接口信息 */ void simulate_i2c_send_ack(simulate_i2c_t *i2c_info) { // SDA输出模式 simulate_i2c_config_sda_out(i2c_info); // SDA=0 simulate_i2c_sda_out_low(i2c_info); delay_us(i2c_info->delay_time); // SCL发送一个脉冲 simulate_i2c_scl_out_high(i2c_info); delay_us(i2c_info->delay_time); simulate_i2c_scl_out_low(i2c_info); delay_us(i2c_info->delay_time); return ; } /* * 给从设备发送一个no ack非应答信号 * @i2c_info i2c接口信息 */ void simulate_i2c_send_no_ack(simulate_i2c_t *i2c_info) { // SDA输出模式 simulate_i2c_config_sda_out(i2c_info); // SDA=1 simulate_i2c_sda_out_high(i2c_info); delay_us(i2c_info->delay_time); // SCL发送一个脉冲 simulate_i2c_scl_out_high(i2c_info); delay_us(i2c_info->delay_time); simulate_i2c_scl_out_low(i2c_info); delay_us(i2c_info->delay_time); return ; } /* * 读取从设备的ack应答信号 * @i2c_info i2c接口信息 * @ret 读取到的信号。0表示应答,1表示非应答 */ unsigned int simulate_i2c_read_ack(simulate_i2c_t *i2c_info) { unsigned int ack = 1; // SDA输入模式,释放SDA simulate_i2c_config_sda_in(i2c_info); delay_us(i2c_info->delay_time); simulate_i2c_scl_out_high(i2c_info); delay_us(i2c_info->delay_time); ack = simulate_i2c_sda_in(i2c_info); simulate_i2c_scl_out_low(i2c_info); delay_us(i2c_info->delay_time); return ack; } /* * 主设备从从设备那里读取一个8bit数据 * @i2c_info i2c接口信息 * @ret 读取的数据 */ unsigned char simulate_i2c_read_byte(simulate_i2c_t *i2c_info) { int i; unsigned char data = 0; // SDA输入模式 simulate_i2c_config_sda_in(i2c_info); for (i=0; i<8; i++) { delay_us(i2c_info->delay_time); simulate_i2c_scl_out_high(i2c_info); delay_us(i2c_info->delay_time); // 读取一个bit data <<= 1; if (gpio_level_high == simulate_i2c_sda_in(i2c_info)) data |= 0x01; simulate_i2c_scl_out_low(i2c_info); } return data; } /* * 主设备写8bit数据到从设备 * @i2c_info i2c接口信息 * @data 待写数据 */ void simulate_i2c_write_byte(simulate_i2c_t *i2c_info, unsigned char data) { int i; // SDA输出模式 simulate_i2c_config_sda_out(i2c_info); for (i=0; i<8; i++) { delay_us(i2c_info->delay_time); // 写一个bit if (data & 0x80) simulate_i2c_sda_out_high(i2c_info); else simulate_i2c_sda_out_low(i2c_info); delay_us(i2c_info->delay_time); simulate_i2c_scl_out_high(i2c_info); delay_us(i2c_info->delay_time); simulate_i2c_scl_out_low(i2c_info); data <<= 1; } delay_us(i2c_info->delay_time); return ; }
simulate_i2c.h
// 模拟i2c的头文件
#ifndef __OPENLOONGSON_SIMULATE_H
#define __OPENLOONGSON_SIMULATE_H
// 模拟i2c的接口信息 typedef struct { unsigned int scl_gpio; // SCL所在gpio引脚 unsigned int sda_gpio; // SDA所在gpio引脚 int delay_time; // 周期的1/2,单位us }simulate_i2c_t; /* * 模拟i2c初始化 * @i2c_info i2c的接口信息 */ void simulate_i2c_init(simulate_i2c_t *i2c_info); /* * 模拟I2C的开始 * @i2c_info i2c接口信息 */ void simulate_i2c_start(simulate_i2c_t *i2c_info); /* * 模拟I2C的停止 * @i2c_info i2c接口信息 */ void simulate_i2c_stop(simulate_i2c_t *i2c_info); /* * 给从设备发送一个ack应答信号 * @i2c_info i2c接口信息 */ void simulate_i2c_send_ack(simulate_i2c_t *i2c_info); /* * 给从设备发送一个no ack非应答信号 * @i2c_info i2c接口信息 */ void simulate_i2c_send_no_ack(simulate_i2c_t *i2c_info); /* * 读取从设备的ack应答信号 * @i2c_info i2c接口信息 * @ret 读取到的信号。0表示应答,1表示非应答 */ unsigned int simulate_i2c_read_ack(simulate_i2c_t *i2c_info); /* * 主设备从从设备那里读取一个8bit数据 * @i2c_info i2c接口信息 * @ret 读取的数据 */ unsigned char simulate_i2c_read_byte(simulate_i2c_t *i2c_info); /* * 主设备写8bit数据到从设备 * @i2c_info i2c接口信息 * @data 待写数据 */ void simulate_i2c_write_byte(simulate_i2c_t *i2c_info, unsigned char data);
#endif
完整的代码请到git查看,谢谢欣赏。
相关文章推荐
- 【龙芯1c库】封装硬件I2C接口和使用示例
- 【龙芯1c库】封装引脚复用接口和使用示例
- 【龙芯1c库】封装硬件定时器接口和使用示例
- 【龙芯1c库】封装gpio接口和使用示例
- 【龙芯1c库】封装硬件pwm接口和使用示例
- 【龙芯1c库】封装时钟接口和使用示例
- 【龙芯1c库】封装软件延时接口和使用示例
- 【龙芯1c库】封装硬件SPI接口和使用示例
- 【龙芯1c库】封装systick系统滴答定时器接口和使用示例
- STM32F1使用I/0模拟I2C接口
- 使用Carlos Antollini封装的ADO2类示例
- JAVA中常用接口的介绍及使用示例:java.lang.Comparable
- 如何使用W7100A模拟I2C总线
- 项目过程中如何使用面向对象的特征:继承,封装,多态,接口
- msm 模拟i2c使用过程分析
- msm 模拟i2c使用过程分析
- Tolua使用,利用pkg文件,封装自己的lua支持的cocos2dx的接口
- Java枚举(用Java普通类模拟枚举的实现原理及JDK枚举API使用示例)
- linux gpio模拟i2c的使用
- 天气预报接口使用及示例