嵌入式爱好者

查看: 11629|回复: 13

[Linux] linux系统下的s3c6410定时器驱动+温度湿度传感器驱动程序源代码

[复制链接]

0

主题

0

帖子

3

积分

扫一扫,手机访问本帖
发表于 2013-10-12 10:52:53 | 显示全部楼层 |阅读模式
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <plat/regs-timer.h>
#include <mach/regs-irq.h>
#include <asm/mach/time.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>

#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>

#include <plat/gpio-cfg.h>
#include <mach/gpio-bank-a.h>
#include <mach/gpio-bank-b.h>
#include <mach/gpio-bank-c.h>
#include <mach/gpio-bank-d.h>
#include <mach/gpio-bank-e.h>
#include <mach/gpio-bank-f.h>
#include <mach/gpio-bank-g.h>
#include <mach/gpio-bank-h.h>
#include <mach/gpio-bank-i.h>
#include <mach/gpio-bank-j.h>
#include <mach/gpio-bank-k.h>
#include <mach/gpio-bank-m.h>
#include <mach/gpio-bank-n.h>
#include <mach/gpio-bank-o.h>
#include <mach/gpio-bank-p.h>
#include <mach/gpio-bank-q.h>

#define DEVICE_NAME "timer0"  

//the sensor var

unsigned tmp_sensor;
unsigned int shidu=0;
unsigned int temperature=0;
int check=0;

#define  Sensor_SDA1_HIGH  s3c6410_ioSetData(C,0,1)    //GPC0 high
#define  Sensor_SDA1_LOW   s3c6410_ioSetData(C,0,0)
#define  Sensor_SDA1_IN    s3c6410_ioSetDir(C,0,0)
#define  GET_Sensor_SDA1   tmp_sensor=readl(S3C64XX_GPCDAT);tmp_sensor=temp_sensor&0x01

unsigned char Sensor_Data[5]={0};
unsigned char Sensor_Check=0;                  //校验和

unsigned char Sensor_AnswerFlag=0;  //收到起始标志位
unsigned char Sensor_ErrorFlag=0;   //读取传感器错误标志
unsigned int  Sys_CNT=0;


extern  int s3c6410_ioSetData(char IO_id ,unsigned char IO_number,unsigned char status );
extern  int s3c6410_ioSetDir(char IO_id ,unsigned char IO_number,unsigned char status );


unsigned int count_timer0=0;
unsigned int tmp_timer0=0;
unsigned int sensor_time=0;

//传感器函数部分
/********************************************\
|* 功能: 读传感器发送单个字节                *|
\********************************************/
unsigned char Read_SensorData()
  {
        unsigned char i,cnt;
        unsigned char buffer,tmp;
        buffer = 0;

        for(i=0;i<8;i++)
        {
                cnt=0;

                while(!(GET_Sensor_SDA1,temp_sensor))        //检测上次低电平是否结束 一旦有高电平,延时30us后看一下还是否是高电平,若还是则是1若不是则是0
                {
                  if(++cnt >= 39)   //>50us循环一次刚好是64个clk 1.28us
                   {
                          break;
                   }
                }
                //延时Min=26us Max50us 跳过数据"0" 的高电平
                udelay(30);         //延时30us

                //判断传感器发送数据位
                tmp =0;
                if((GET_Sensor_SDA1,temp_sensor))
                {
                  tmp = 1;
                }
                cnt =0;
                while((GET_Sensor_SDA1,temp_sensor))                //等待高电平 结束
                {
                           if(++cnt >= 20)  //>35us
                        {
                          break;
                        }
                }
                buffer <<=1;
                buffer |= tmp;
        }
        return buffer;
  }

/********************************************\
|* 功能: 读传感器
返回值:0错误 1正确
\********************************************/
unsigned char Read_Sensor()
  {
         unsigned char i;
        //主机拉低(Min=800USMax=20Ms)
         Sensor_SDA1_LOW;  //拉低
         udelay(2000);   //延时2Ms

        //释放总线 延时(Min=30us Max=50us) 拉高30us
         Sensor_SDA1_HIGH;
         udelay(38); // 拉高 30到40us
        //主机设为输入 判断传感器响应信号
        Sensor_SDA1_IN;//主机设置为输入

        Sensor_AnswerFlag = 0;  // 传感器响应标志

        //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
        if(GET_Sensor_SDA1==0)
        {
           Sensor_AnswerFlag = 1;//收到起始信号
           Sys_CNT = 0;
           //判断从机是否发出 80us 的低电平响应信号是否结束
           while(!(GET_Sensor_SDA1,temp_sensor))//如果为0,则一直在这里循环 一旦有高电平则执行下边的语句
           {
             if(++Sys_CNT>60)     //防止进入死循环>80us
                 {
                   Sensor_ErrorFlag = 1;
                   return 0;
                  }
            }
            Sys_CNT = 0;
            //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
            while((GET_Sensor_SDA1,temp_sensor))
            {
               if(++Sys_CNT>60)     //防止进入死循环>80us  实际是50us
                   {
                     Sensor_ErrorFlag = 1;
                     return 0;
                   }
            }
            // 数据接收        传感器共发送40位数据
            // 即5个字节 高位先送  5个字节分别为湿度高位 湿度低位 温度高位 温度低位 校验和
            // 校验和为:湿度高位+湿度低位+温度高位+温度低位
            for(i=0;i<5;i++)
            {
              Sensor_Data[i] = Read_SensorData();
            }
          }
          else
          {
            Sensor_AnswerFlag = 0;          // 未收到传感器响应
          }
          return 1;
  }
   




static irqreturn_t Mytimer0_Interupt(int irq,void *dev_id)
{
       
       if(irq!=IRQ_TIMER0)
        {
        printk(KERN_NOTICE "bad irq % d in timer0 \n", irq);
        return -1;
        }
       
        //传感器部分   要求至少2.4秒一次
        if(sensor_time==120)
        {
        sensor_time=0;
    Read_Sensor();
        check=Sensor_Data[0]+Sensor_Data[1]+Sensor_Data[2]+Sensor_Data[3];
        if(Sensor_Data[4]==check)
        {
        temperature = (float)(Sensor_Data[2]*256+Sensor_Data[3]);
        shidu=(float)(Sensor_Data[0]*256+Sensor_Data[1]);
       
        }
        else
                {
                temperature=0;
                shidu=0;
                }
    printk(KERN_NOTICE "The temperature is:%-4.1f\n",temperature);
        printk(KERN_NOTICE "The shidu is:%-4.1f\n",shidu);       
        }       
        //计数部分
        count_timer0++;        
                if(count_timer0==50)
                {
        printk(KERN_NOTICE "timer_irq is ok:%d \n", count_timer0);
                count_timer0=0;
                tmp_timer0++;
                if(tmp_timer0>=2)
                tmp_timer0=0;
               
                if(tmp_timer0==0)
                s3c6410_ioSetData('M',0,0);//亮
                else
                s3c6410_ioSetData('M',0,1);//灭
                }
                return IRQ_HANDLED;
         //        return 0;       
}

//cmd:0:stop,1:start
//arg: reserved
static long s3c6410_Timer0(struct file *filp, unsigned int cmd, unsigned long arg)
{      
        //printk(KERN_NOTICE "timer0 is ok 1\n");
        //printk(KERN_ALERT "timer0 is ok 2\n");
        unsigned long tcfg0;//寄存器0x00
        unsigned long tcfg1;//寄存器0x04
        unsigned long tcon;  //控制寄存器 0x08
        unsigned int tcnt;  //计数值
        unsigned long tint;//中断寄存器 0x44
        s3c6410_ioSetDir('M',0,1);
                tcon = __raw_readl(S3C_TCON);  
                tint = __raw_readl(S3C64XX_TINT_CSTAT);
            tcfg1 = __raw_readl(S3C_TCFG1);
                tcfg0 = __raw_readl(S3C_TCFG0);
               
         if (cmd == 0)
         {         
         tcon&=~(1<<0);
         tint&=~(1<<0);
         __raw_writel(tcon, S3C_TCON);
         __raw_writel(tint, S3C64XX_TINT_CSTAT);
         }
         
         else
         {
         //设置分频比
         tcfg0 &= ~S3C_TCFG_PRESCALER0_MASK;   
         tcfg0 |= (66-1);           

         tcfg1&=~S3C_TCFG1_MUX0_MASK;
         tcfg1|=S3C_TCFG1_MUX0_DIV4;
       
         __raw_writel(tcfg0, S3C_TCFG0);
         __raw_writel(tcfg1, S3C_TCFG1);
         
         

         tcnt=5000;     //0.02s
         __raw_writel(tcnt, S3C_TCNTB(0));
         __raw_writel(tcnt/2, S3C_TCMPB(0));

        tint|=1<<0;
        __raw_writel(tint, S3C64XX_TINT_CSTAT);
        tcon&=~(0x0f<<0);
        tcon|=0x0b;
        __raw_writel(tcon, S3C_TCON);
       
        tcon &= ~0x2<<0; //clear manual update bit
        __raw_writel(tcon, S3C_TCON);
         }
         return 0;
         
}

static struct file_operations dev_fops = {
    .owner                        = THIS_MODULE,
    .unlocked_ioctl        = s3c6410_Timer0,
};

static struct miscdevice misc = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = DEVICE_NAME,
        .fops = &dev_fops,
};
static int __init dev_init(void)
{
        int ret;
        int ret1;
        ret1 = misc_register(&misc);
        ret=request_irq(IRQ_TIMER0,Mytimer0_Interupt,IRQ_TYPE_LEVEL_HIGH,DEVICE_NAME,NULL);
        if(ret<0)
        {printk(KERN_NOTICE "Register IOPWM failed!\n");
        return ret;
        }
        printk (KERN_NOTICE "timer0 interrupt is ok! \n");
        return ret1;
       
           
}

static void __exit dev_exit(void)  
{
        free_irq(IRQ_TIMER0,NULL);
        misc_deregister(&misc);
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jack Sun");
MODULE_DESCRIPTION("S3C6410 Timer0 Driver");
回复

使用道具 举报

0

主题

0

帖子

3

积分

 楼主| 发表于 2013-10-12 10:55:06 | 显示全部楼层
没有示波器,传感器部分未成功,定时器可以工作了
点评回复 支持 反对

使用道具 举报

153

主题

3910

帖子

4207

积分

AM5718通行证AM335x通行证i.MX6UL通行证i.MX RT通行证i.MX6Q通行证XX18通行证TCU通行证FCU1401通行证FCU1301通行证FCU11xx通行证

发表于 2013-10-12 16:27:50 | 显示全部楼层
你看看是不是你的驱动和系统里面的驱动同时调用的同一个管脚
技术支持电话:0312-3119192
技术支持邮箱:Linux@forlinx.com
点评回复 支持 反对

使用道具 举报

0

主题

0

帖子

3

积分

 楼主| 发表于 2013-10-12 17:25:13 | 显示全部楼层
飞凌-unix 发表于 2013-10-12 16:27
你看看是不是你的驱动和系统里面的驱动同时调用的同一个管脚

哦哦~系统里的驱动?是什么意思,我用io口模拟I2C协议,对传感器进行控制,您的意思是系统里的驱动将io的时序搞乱了吗?
点评回复 支持 反对

使用道具 举报

恨水长东 该用户已被删除
发表于 2014-4-23 16:22:27 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
点评回复 支持 反对

使用道具 举报

153

主题

3910

帖子

4207

积分

AM5718通行证AM335x通行证i.MX6UL通行证i.MX RT通行证i.MX6Q通行证XX18通行证TCU通行证FCU1401通行证FCU1301通行证FCU11xx通行证

发表于 2014-4-23 17:36:28 | 显示全部楼层
恨水长东 发表于 2014-4-23 16:22
楼主求单独的定时器程序和测试程序啊!!!求求你了

私信楼主,他不一定看帖子
技术支持电话:0312-3119192
技术支持邮箱:Linux@forlinx.com
点评回复 支持 反对

使用道具 举报

恨水长东 该用户已被删除
发表于 2014-4-24 07:37:43 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
点评回复 支持 反对

使用道具 举报

153

主题

3910

帖子

4207

积分

AM5718通行证AM335x通行证i.MX6UL通行证i.MX RT通行证i.MX6Q通行证XX18通行证TCU通行证FCU1401通行证FCU1301通行证FCU11xx通行证

发表于 2014-4-25 08:46:02 | 显示全部楼层
恨水长东 发表于 2014-4-24 07:37
谢谢委员长,我想知道关于定时器寄存器的头文件是哪一个呢

我在你的另一个帖子中回复你了,估计你是没有去查看吧,地址连接:http://bbs.witech.com.cn/forum.p ... %3D27%26typeid%3D27
技术支持电话:0312-3119192
技术支持邮箱:Linux@forlinx.com
点评回复 支持 反对

使用道具 举报

恨水长东 该用户已被删除
发表于 2014-4-25 09:07:46 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
点评回复 支持 反对

使用道具 举报

恨水长东 该用户已被删除
发表于 2014-4-25 09:09:55 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
点评回复 支持 反对

使用道具 举报

恨水长东 该用户已被删除
发表于 2014-4-25 09:13:18 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
点评回复 支持 反对

使用道具 举报

恨水长东 该用户已被删除
发表于 2014-4-25 09:14:02 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
点评回复 支持 反对

使用道具 举报

恨水长东 该用户已被删除
发表于 2014-4-25 09:14:50 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
点评回复 支持 反对

使用道具 举报

学学学 该用户已被删除
发表于 2014-4-25 13:56:23 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
点评回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋| 飞凌嵌入式 ( 冀ICP备12004394号-1 )

GMT+8, 2024-12-21 16:22

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表