ARM开发之基于IIC协议的TM1650驱动实现(模拟IIC实现)

这篇具有很好参考价值的文章主要介绍了ARM开发之基于IIC协议的TM1650驱动实现(模拟IIC实现)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、内存映射

1、什么是内存映射?为什么要内存映射?

2、gec6818如何进行内存映射?(相关的函数)

3、内存映射代码 :

二、模拟IIC的底层代码实现

1、配置输入输出方向

2、拉高拉低引脚

3、获得总线传回的数据

4、协议的实现

三、TM1650的使用

1、TM1650简介

2、TM1650怎么驱动?

2.1 控制命令

 2.2 显存地址

 2.3 对显存地址写数据时序

四、针对TM1650实现的IIC驱动

1、TM1650模块驱动(完整驱动代码)

2、驱动测试程序

3、Makefile

4、Linux操作

关键词:

1、模拟IIC协议

2、S5P6818

3、ARM内存访问控制

4、TM1650数码管

本片博客记录在gec6818平台上的模拟IIC实现,并成功驱动 TM1650 数码管

模拟IIC也可适用其他所有用IIC协议驱动的外设!

如文章有错误,请各位不吝赐教。


一、内存映射

1、什么是内存映射?为什么要内存映射?

外设的SFR(特殊功能寄存器)编址与内存的编址是同一个地址空间,叫做IO内存
但是当内核想要访问某些特殊寄存器或者内存单元的时候,不能直接使用IO内存的物理地址进行访问,而要通过该物理地址所对应的虚拟地址进行访问,因此,必须要进行地址的转换,而从物理地址到虚拟地址的映射我们就称为内存映射。

2、gec6818如何进行内存映射?(相关的函数)

//struct resource *
#include <linux/ioport.h> 

//ioremap iounmap 之类的函数
#include <linux/io.h> 
/*

ioremap函数

1、参数:
offset:要映射的物理内存区的起始地址
size:物理地址的范围

2、返回值:
虚拟地址的指针

3、头文件引用:
#include <linux/io.h>

*/
static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size);


/*

iounmap函数

1、参数:
io_addr:虚拟地址的指针

2、返回值:
无

3、头文件引用:
#include <linux/io.h>

*/
void __iounmap(volatile void __iomem *io_addr);

3、内存映射代码 :

//1、定义SCL、SDA的GPIO虚拟内存指针
static void __iomem * IIC_OUT_VA; //0x00
static void __iomem * IIC_OUTENB_VA; //0x04
static void __iomem * IIC_ALTFN0_VA; //0x20
static void __iomem * IIC_ALTFN1_VA; //0x24
static void __iomem * IIC_PAD_VA; //0x18

//1、定义tm1650设备结构体
struct miscdevice tm1650_IIC_misc = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "tm1650_drv",
	.fops = &tm1650_IIC_fops,
};

//2、IO内存的动态映射,由物理地址得到虚拟地址
//这里用到 GPIOC7 GPIOC8 两个引脚  查阅GPIOC的基址
IIC_OUT_VA = ioremap(0xc001c000, 0x1000);
if(IIC_OUT_VA == NULL){
	printk("ioremap error\n");
	misc_deregister(&tm1650_IIC_misc);
	return -EBUSY;
}	

//3、得到每个寄存器的虚拟地址(根据s5p6818文档查阅)
IIC_OUTENB_VA = IIC_OUT_VA + 0x04; //0x04
IIC_ALTFN0_VA = IIC_OUT_VA + 0x20; //0x20
IIC_ALTFN1_VA = IIC_OUT_VA + 0x24; //0x24
IIC_PAD_VA    = IIC_OUT_VA + 0x18; //0x18

下面讲解上述的代码以及如何在文档查阅物理地址和偏移量:

1)三星s5p6818文档的这个部分是讲GPIO控制器的,相关寄存器解说就在这里。

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

2) 查看寄存器描述,可以知道基址(Base Address)以及各寄存器的偏移(Offset),当然大家也可以看后面的描述(Description)来了解一下各寄存器的作用是什么。tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

 3)举例来说,譬如我实验的IIC引脚用的GPIO是GPIOC,那么配置输出模式的寄存器GPIOCOUT基址就为 0xc001c000 ,偏移就为 0x1000。

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

 所以也就可以看到内存映射代码的ioremap函数参数(上面)写的是:

IIC_OUT_VA = ioremap(0xc001c000, 0x1000);

同理,我们想找到 GPIOCOUTENB 寄存器的物理地址也就很简单了,也就是:

基址+偏移:

GPIOCOUTENB  = 0xc001c000  +  0x004;

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

 但是!!我们不用都去使用基址+偏移找到其物理地址,再用ioremap进行映射获得虚拟地址给内核使用,因为我们可以发现:

每个GPIOXOUT寄存器偏移都为 0x1000 ,后面的寄存器(譬如GPIOXENB......等)偏移都在 0x1000内(GPIOXENB的偏移是 0x004),也就是说我们可以根据GPIOXOUT寄存器的首地址来找到其他寄存器,这个“首地址”可以是物理地址,也可以是ioremap后的虚拟地址,偏移量都生效。所以明白了这点之后,我们就不用对每个寄存器进行ioremap来获得虚拟地址,我们只需要获得GPIOXOUT的虚拟地址,然后用该虚拟地址加上偏移量就可以获得其他寄存器的虚拟地址!也就说我们只使用了一次ioremap,巧妙地使用了偏移量

因此就可以看到上面内存映射代码:

//得到每个寄存器的虚拟地址
IIC_OUTENB_VA = IIC_OUT_VA + 0x04; //0x04
IIC_ALTFN0_VA = IIC_OUT_VA + 0x20; //0x20
IIC_ALTFN1_VA = IIC_OUT_VA + 0x24; //0x24
IIC_PAD_VA    = IIC_OUT_VA + 0x18; //0x18

总结:至此,内存映射我们就完成了,我们找到了相关寄存器的虚拟地址,我们就可以使用这些虚拟地址进行读写以控制IO,来实现IIC。

二、模拟IIC的底层代码实现

     模拟IIC通信将涉及到SDA、SCL的

  1. 配置输入输出方向
  2. 拉高拉低
  3. 获得总线传回的数据
  4. 协议的实现(起始、结束信号等)

1、配置输入输出方向

主要是SDA的方向需要配置,SCL只是时钟线

void SDA_OUT(void){
	(*(unsigned int *)IIC_OUTENB_VA) |= (1<<8);
}

void SDA_IN(void){
	(*(unsigned int *)IIC_OUTENB_VA) &= ~(1<<8);
}

可以看到我们操作的是上面我们通过内存映射获得的虚拟地址(IIC_OUTENB_VA),通过对这个虚拟地址的读写来对寄存器进行读写,达到控制GPIO的作用。

2、拉高拉低引脚

SCL

void SCL_set0(void){
	(*(unsigned int *)IIC_OUT_VA) &= ~(1<<7);
}

void SCL_set1(void){
	(*(unsigned int *)IIC_OUT_VA) |= (1<<7);
}

SDA

void SDA_set0(void){
	(*(unsigned int *)IIC_OUT_VA) &= ~(1<<8);
}

void SDA_set1(void){
	(*(unsigned int *)IIC_OUT_VA) |= (1<<8);
}

3、获得总线传回的数据

char SDA_VAL(void){
	return ((*(unsigned int *)IIC_PAD_VA) >> 8)&0X01;
}

4、协议的实现

//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
	SDA_set1();	  	  
	SCL_set1();
	udelay(2);
 	SDA_set0();//START:when CLK is high,DATA change form high to low 
	udelay(2);
	SCL_set0();//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	SCL_set0();
	SDA_set0();//STOP:when CLK is high DATA change form low to high
	udelay(2);
	SCL_set1(); 
	SDA_set1();//发送I2C总线结束信号
	udelay(2);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	SDA_set1();udelay(2);	   
	SCL_set1();udelay(2);	 
	while(SDA_VAL())//
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	SCL_set0();//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
	SCL_set0();
	SDA_OUT();
	SDA_set0();
	udelay(2);
	SCL_set1();
	udelay(2);
	SCL_set0();
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	SCL_set0();//SCL = 0
	SDA_OUT();//SDA设为输出
	SDA_set1();//SDA置高平
	udelay(2);
	SCL_set1();
	udelay(2);
    SCL_set0();
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
    SCL_set0();//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
		if(((txd&0x80)>>7) == 1)
			SDA_set1();
		else if(((txd&0x80)>>7) == 0)
			SDA_set0();
        txd<<=1; 	  
		    SCL_set1();
		    udelay(2); 
		    SCL_set0();	
		    udelay(2);
    }	 
} 	    

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        SCL_set0(); 
        udelay(2);
		SCL_set1();
        receive<<=1;
        if(SDA_VAL())receive++;   
		udelay(2); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

总结:至此我们就实现了模拟IIC,根据相关外设的IIC通信时序的要求,我们就可以实现与外设的IIC通信。下面我们就来实现IIC设备 TM1650 控制。

三、TM1650的使用

1、TM1650简介

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

2、TM1650怎么驱动?

2.1 控制命令

我们只用模式命令来显示数码管  0x48

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

 2.2 显存地址

写LED显示数据的时候,按照从显示地址从高位到低位,从数据字节的高位到低位操作。

1)DIG1~DIG4 :数码管第一位到第四位。

2)显存地址 :0x68 0x6A 0x6C 0x6E

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linuxtm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

 2.3 对显存地址写数据时序

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

1)显示数据码表 NUM[10]

/* TM1650 码表*/
const uint8_t NUM[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

2)根据文档时序,封装写字节函数 TM1650_Wr_RAM(uint8_t Address, uint8_t Data)

/* TM1650 写字节函数 */
void TM1650_Wr_RAM(uint8_t Address, uint8_t Data)
{
    IIC_Start();
    IIC_Send_Byte(Address);
    IIC_Wait_Ack();
    IIC_Send_Byte(Data);
    IIC_Wait_Ack();
    IIC_Stop();
}

3)往显存写数据显示数据,同样我们封装成函数 set_number(char mode, int num)

/* 
	TM1650 写入数字函数 
	第一位:num / 1000
	第二位:小数点.
	第三位:num % 100 / 10   --十位
	第四位:num % 10             --个位
*/
void set_number(char mode, int num)
{
	TM1650_Wr_RAM(0x68, NUM[num / 1000]);
	if(mode == 1)
	{
		TM1650_Wr_RAM(0x6A, 0X80);// 第二位只显示小数点
	}
	else
	{
		TM1650_Wr_RAM(0x6A, NUM[num % 1000 / 100]);// 第二位显示正常数据
	}	
	TM1650_Wr_RAM(0x6C, NUM[num % 100 / 10]);
	TM1650_Wr_RAM(0x6E, NUM[num % 10]);
}

 4)打开显示设置命令:

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

//初始化TM1650模块
TM1650_Wr_RAM(0x48, 0x71);

四、针对TM1650实现的IIC驱动

1、TM1650模块驱动(完整驱动代码)

下面是源文件:tm1650_drv.c

使用 insmod 插入模块 tm1650_drv.ko:

[root@GEC6818 /IOT/tangJW/a53_10]#insmod tm1650_drv

#include <linux/module.h>
#include <linux/printk.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <mach/platform.h>
#include <linux/errno.h>
#include <linux/ioport.h> //struct resource *
#include <linux/io.h> //ioremap
#include <linux/uaccess.h> //copy_from_user
#include <linux/gpio.h>
#include <linux/delay.h>

//定义SCL、SDA的GPIO虚拟内存指针
static void __iomem * IIC_OUT_VA; //0x00
static void __iomem * IIC_OUTENB_VA; //0x04
static void __iomem * IIC_ALTFN0_VA; //0x20
static void __iomem * IIC_ALTFN1_VA; //0x24
static void __iomem * IIC_PAD_VA; //0x18

void SDA_OUT(void){
	(*(unsigned int *)IIC_OUTENB_VA) |= (1<<8);
}

void SDA_IN(void){
	(*(unsigned int *)IIC_OUTENB_VA) &= ~(1<<8);
}

void SDA_set0(void){
	(*(unsigned int *)IIC_OUT_VA) &= ~(1<<8);
}

void SDA_set1(void){
	(*(unsigned int *)IIC_OUT_VA) |= (1<<8);
}

char SDA_VAL(void){
	return ((*(unsigned int *)IIC_PAD_VA) >> 8)&0X01;
}

void SCL_set0(void){
	(*(unsigned int *)IIC_OUT_VA) &= ~(1<<7);
}

void SCL_set1(void){
	(*(unsigned int *)IIC_OUT_VA) |= (1<<7);
}

//模拟IIC协议用到的函数

//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
	SDA_set1();	  	  
	SCL_set1();
	udelay(2);
 	SDA_set0();//START:when CLK is high,DATA change form high to low 
	udelay(2);
	SCL_set0();//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	SCL_set0();
	SDA_set0();//STOP:when CLK is high DATA change form low to high
	udelay(2);
	SCL_set1(); 
	SDA_set1();//发送I2C总线结束信号
	udelay(2);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	SDA_set1();udelay(2);	   
	SCL_set1();udelay(2);	 
	while(SDA_VAL())//
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	SCL_set0();//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
	SCL_set0();
	SDA_OUT();
	SDA_set0();
	udelay(2);
	SCL_set1();
	udelay(2);
	SCL_set0();
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	SCL_set0();//SCL = 0
	SDA_OUT();//SDA设为输出
	SDA_set1();//SDA置高平
	udelay(2);
	SCL_set1();
	udelay(2);
    SCL_set0();
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
    SCL_set0();//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
		if(((txd&0x80)>>7) == 1)
			SDA_set1();
		else if(((txd&0x80)>>7) == 0)
			SDA_set0();
        txd<<=1; 	  
		    SCL_set1();
		    udelay(2); 
		    SCL_set0();	
		    udelay(2);
    }	 
} 	    

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        SCL_set0(); 
        udelay(2);
		SCL_set1();
        receive<<=1;
        if(SDA_VAL())receive++;   
		udelay(2); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

//------------- TM1650 @TangJW ---------------
/* TM1650 码表*/
const uint8_t NUM[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

/* TM1650 写字节函数 */
void TM1650_Wr_RAM(uint8_t Address, uint8_t Data)
{
    IIC_Start();
    IIC_Send_Byte(Address);
    IIC_Wait_Ack();
    IIC_Send_Byte(Data);
    IIC_Wait_Ack();
    IIC_Stop();
}

/* 
	TM1650 写入数字函数 
	第一位:num / 1000
	第二位:小数点.
	第三位:num % 100 / 10   --十位
	第四位:num % 10             --个位
*/
void set_number(char mode, int num)
{
	TM1650_Wr_RAM(0x68, NUM[num / 1000]);
	if(mode == 1)
	{
		TM1650_Wr_RAM(0x6A, 0X80);// 第二位只显示小数点
	}
	else
	{
		TM1650_Wr_RAM(0x6A, NUM[num % 1000 / 100]);// 第二位显示正常数据
	}	
	TM1650_Wr_RAM(0x6C, NUM[num % 100 / 10]);
	TM1650_Wr_RAM(0x6E, NUM[num % 10]);
}

// 定义字符设备的文件操作集
/* 
	open函数:
	初始化TM1650模块 
*/
int TM1650_open(struct inode *inode, struct file *filp)
{
	//初始化TM1650模块
	TM1650_Wr_RAM(0x48, 0x71);
	
	printk("TM1650_init! \n");
	return 0;
}

/*
	ioctl函数:实现set_number
	cmd:数据参数
	args:
	  --0  第二位显示正常数据
	  --1  第二位显示小数点
*/
static void TM1650_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
	set_number(args, cmd);
}

//定义文件操作集
const struct file_operations tm1650_IIC_fops = {
	.owner = THIS_MODULE,
	.open = TM1650_open,
	.unlocked_ioctl = TM1650_ioctl,
};

struct miscdevice tm1650_IIC_misc = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "tm1650_drv",
	.fops = &tm1650_IIC_fops,
};

/* 
	TM1650初始化
	-SCL: GPIOC 7
	-SDA: GPIOC 8
*/
static int __init TM1650_init(void)
{
	int ret;
	
	printk("TM1650_init... \n");
    //注册混杂设备
	ret =  misc_register(&tm1650_IIC_misc);
	if(ret < 0)
	{
		printk("misc_register error\n");
		return -EBUSY;
	}

	//IO内存的动态映射,由物理地址得到虚拟地址  GPIOC7 GPIOC8
	IIC_OUT_VA = ioremap(0xc001c000, 0x1000);
	if(IIC_OUT_VA == NULL){
		printk("ioremap error\n");
		misc_deregister(&tm1650_IIC_misc);
		return -EBUSY;
	}	

	//得到每个寄存器的虚拟地址
  	IIC_OUTENB_VA = IIC_OUT_VA + 0x04; //0x04
  	IIC_ALTFN0_VA = IIC_OUT_VA + 0x20; //0x20
  	IIC_ALTFN1_VA = IIC_OUT_VA + 0x24; //0x24
  	IIC_PAD_VA    = IIC_OUT_VA + 0x18; //0x18
	
	//访问虚拟地址:GPIOC7 SCL         GPIOC8 SDA
	//将引脚设置成普通的GPIO
	*(unsigned int *)IIC_ALTFN0_VA &=~((3<<14) + (3<<16));
	*(unsigned int *)IIC_ALTFN0_VA |=((1<<14) + (1<<16));

	//将2个GPIO设置为输出
	*(unsigned int *)IIC_OUTENB_VA |= ((1<<7)+(1<<8));
	
	//2个GPIO输出高电平,IIC默认是释放模式
	*(unsigned int *)IIC_OUT_VA |= ((1<<7)+(1<<8));

	return ret;
}

static void __exit TM1650_exit(void)
{
	iounmap(IIC_OUT_VA);
	misc_deregister(&tm1650_IIC_misc);
}

module_init(TM1650_init);
module_exit(TM1650_exit);

MODULE_AUTHOR("tangjingwei@qq.com");
MODULE_DESCRIPTION("IIC Device /TM1650/ Driver @TangJW");
MODULE_LICENSE("GPL");

2、驱动测试程序

下面是源文件:tm1650_test.c

测试程序运行:

1、第二个参数为 1,控制第二位总是显示小数点

[root@GEC6818 /IOT/tangJW/a53_10]#./tm1650_test 2023 1

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

 2、第二个参数为 0,控制第二位显示正常数据

[root@GEC6818 /IOT/tangJW/a53_10]#./tm1650_test 2023 0

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

/*****************************

TM1650测试函数,请配合 tm1650_drv.ko 使用
作者:唐京伟 
联系:tangjingwei@qq.com

IIC测试硬件引脚:
-SCL: GPIOC 7
-SDA: GPIOC 8 

*****************************/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv)
{	
	int num, mode;
	
	/* 1、调用设备的open函数(即发送初始化tm1650的iic时序信号)*/
	int fd = open("/dev/tm1650_drv",O_RDWR); 
	if(fd<0){
		perror("open /dev/tm1650_drv failed! ");
		return 0;
	}

	/* 2、调用设备的ioctl函数(即发送控制显示tm1650的iic时序信号)*/
	num = ((int)(argv[1][0]) - 48)*1000 + ((int)(argv[1][1]) - 48)*100 + ((int)(argv[1][2]) - 48)*10 + ((int)(argv[1][3]) - 48);
	mode = (int)(argv[2][0]) - 48;
	printf("Open TM1650 successfully, check it out!\n");
	//mode: 1-第二位显示小数点			0-第二位显示正常数据
	ioctl(fd, num, mode); 

	while(1)
	{		

    }
}

3、Makefile

下面是文件:Makefile

Makefile 注意点:

1、obj-m  应为  tm1650_drv.o 

2、KERNELDIR  应为  自己的Linux环境下的6818源码kernel目录路径

3、CROSS_COMPILE  应为  自己的Linux环境下的交叉编译器路径

4、命令介绍

make 命令:使用交叉编译器编译 tm1650_drv.c

make test 命令:使用arm-linux-gcc编译 tm1650_test.c

obj-m:=tm1650_drv.o


KERNELDIR:=/usr/local/6818GEC/kernel
CROSS_COMPILE:=/usr/local/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
PWD:=$(shell pwd)

default:
	$(MAKE) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules

test:
	arm-linux-gcc tm1650_test.c -o tm1650_test

clean:
	rm -rf *.o *.order .*.cmd *.mod.c *.symvers

4、Linux操作

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

 编译驱动:tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

 编译测试程序:

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

上传文件至开发板,我用的是SecureCRT,并插入模块驱动:

tm1650驱动,ARM-Linux开发,arm开发,单片机,嵌入式硬件,iot,linux

相关文档链接:

三星S5P6818官方文档 + TM1650官方文档     提取码:2023文章来源地址https://www.toymoban.com/news/detail-528598.html

到了这里,关于ARM开发之基于IIC协议的TM1650驱动实现(模拟IIC实现)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32管脚模拟协议驱动双路16位DAC芯片TM8211

    TM8211是一款国产的低成本双路16位DAC驱动芯片,可以应用于普通数模转换领域及音频转换领域等。这里介绍STM32 HAL库驱动TM8211的逻辑,时序和代码。 TM8211的功能特性为: TM8211的内部电路功能框图为: TM8211支持典型的3.3V供电和5V供电,在驱动后进行电压输出时, 需要注意,如以

    2024年02月16日
    浏览(44)
  • GD32E230C8T6《调试篇》之 (软件) IIC通信(主机接收从机) + GN1650驱动芯片 + 按键 + 4位8段数码管显示 (成功)

    IIC也称I2C,是一个多主从的串行总线,由飞利浦公司发明的通讯总线,属于半双工同步传输类总线,仅由两条线就能完成多机通讯,一条SCL时钟线,另外一条双向数据线SDA,IIC总线要求每个设备SCL/SDA线都是漏极开路模式,因此必须带上拉电阻才能正常工作。I2C协议占用引脚少

    2024年01月21日
    浏览(34)
  • Linux设备驱动开发(一) 使用Qemu模拟ARM vexpress-a9开发板

    环境:ubuntu20.04 LTS 参考教材:《Linux设备驱动开发详解——基于最新的Linux4.0内核,宋宝华编著》 1.安装Qemu 安装完成后,在终端输入qemu连按tab键如果出现自动补齐就证明成功安装,如下图所示: 图1 Qemu安装成功示意图 2.安装交叉编译环境 下面验证安装: 图2 交叉编译工具安装

    2024年04月09日
    浏览(50)
  • 模拟IIC通讯协议(stm32)(硬件iic后面在补)

            1、IIC通讯需要两条线就可以,SCL、SDA。         2、IIC的数据传输的速率,不同的ic是不同的,根据电平维持的延时函数的时间来确定IIC数据传输的速率.         3、IIC的延时函数可以使用延时函数,延时函数一般使用系统滴答时钟产生延时,也是在Sysclk频率总线的

    2024年04月15日
    浏览(58)
  • ARM day10 (IIC协议接收温湿传感器数据)

    iic.h si7006.h iic.c si7006.c main.c

    2024年02月16日
    浏览(33)
  • STM32使用IIC协议驱动0.96寸OLED屏

    IIC是常用的协议之一,它通过不同的地址来区分设备,并且端口需要是开漏模式,并且需要接上拉电阻  要使用IIC驱动OLED,首先要配置IIC 然后编写写入函数 ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT) 为判断事件的函数 有以下多种事件 OLED初始化 上图分别为 (起始位

    2024年02月03日
    浏览(36)
  • Linux驱动开发12 IIC驱动

            I2C 是很常用的一个串行通信接口,用于连接各种外设、传感器等器件,在裸机篇已经对 I.MX6U 的 I2C 接口做了详细的讲解。本章我们来学习一下如何在 Linux 下开发 I2C 接口器件驱动,重点是学习 Linux 下的 I2C 驱动框架,按照指定的框架去编写 I2C 设备驱动。     

    2024年02月06日
    浏览(41)
  • STM32 第19讲 IIC(协议简介/读取驱动AT24C02/实验)

    IIC: Inter Integrated Circuit,集成电路总线,是一种 同步 串行 半双工通信协议 ①总线由数据线 SDA 和时钟线 SCL 构成的串行总线,数据线用来传输数据,时钟线用来同步数据收发。 ②总线上每一个器件都有一个唯一的地址识别,所以我们只需要知道器件的地址,根据时序就可以

    2024年02月03日
    浏览(36)
  • 嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM驱动编程第四天-ARM Linux编程之IIC与uart (物联技术666)

    链接:https://pan.baidu.com/s/1V0E9IHSoLbpiWJsncmFgdA?pwd=1688 提取码:1688 教学内容: 1 、 I2C 总线: I2C(Inter-Integrated Circuit),PHILIPS公司开发的两线式半双工同步串行总线;可以用来连接存储器(EEPROM、FLASH)、A/D、D/A转换器、LCD驱动器、传感器等等。 I2C总线有两根信号线:双向数据线

    2024年02月19日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包