linux下多线程采集温度并实时显示----七段数码管(二)

本文主要是围绕数码管的显示、ADC温度采集、按键操作展开,温度的正常阈值保存在eeprom中,当温度的值超过
设定的阈值后,数码管闪烁,蜂鸣器报警。按键可以调节温度的上、下限。

其中,板载的按键可以加热发热电阻进行场景的测试。

注:涉及到驱动文件imx_key.ko lradc.ko可以自己编写或者在我的资源中下载。在编译过程中,对数函数的编译加上 -lm ,多线程的编译加上 -pthread
程序非最终版。中间可以增加互斥锁和线程控制,确保安全稳定。



#include <stdint.h>

#include <unistd.h>

#include <stdio.h>

#include <string.h>

#include <pthread.h>

#include <unistd.h>

#include <stdlib.h>

#include <getopt.h>

#include <fcntl.h>

#include <sys/ioctl.h>

#include <linux/types.h>

#include <linux/spi/spidev.h>

#include <linux/input.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <math.h>



#include "lradc.h"





#define LRADC_DEV     "/dev/magic-adc"   /* adc设备文件名*/

#define CMD_VOLTAGE   IMX28_ADC_CH0      /* 通道0读取命令*/

#define CMD_TEMPTURE  IMX28_ADC_CH1      /* 通道1通读读取命令*/

#define R33             2000

#define V_ADC           3.3

//#define T1            (273.15 + 25)

#define R1              27600

#define B             3435*1000



#define  I2C_SLAVE  0x0703

#define  I2C_ADDR       0xA0  /* EEPROM的从机地址*/

#define  I2C_DEV_NAME  "/dev/i2c-1" /* I2C总线设备文件*/

#define  DATA_ADDR     0x00 /* 保存温度的起始地址*/





#define  SPI_DEVICE   "/dev/spidev1.0"

#define  GPIO_DEVICE  "/sys/class/gpio/gpio117/value"   // gpio3.21的属性文件



#define  ADC_DEV      "/dev/magic-adc"

#define  ADC_MODULE_PATH  "/root/lradc.ko"/* ADC驱动模块的默认路径*/



#define  DIGITRON_ON   1 /* 使能数码管显示*/

#define  DIGITRON_OFF  0 /* 禁能数码管显示*/

#define  DEV_NAME     "/dev/five_buttons"



#define KEY_MODULE_PATH  "/root/imx_key.ko"



#define BEEP_DEV        "/sys/class/leds/beep/brightness" /* 蜂鸣器设备属性文件路径*/





pthread_mutex_t  numlock = PTHREAD_MUTEX_INITIALIZER;/* 静态初始化互斥量*/









static int beep_fd;

static int fd;



static  int show_value[4] ;/* 保存要显示的信息*/



static  int is_show = DIGITRON_ON;/* 保存是否使能数码管显示*/

static  int  i2c_fd;

static  pthread_mutex_t  mutex;

static  int fd;



static uint8_t mode= 0;

static uint8_t bits = 8;

static uint32_t speed = 10000;

static uint16_t delay = 0;

static int fd_spi;

static int fd_gpio;

uint8_t led_value_table[] =   {0xC0, 0xF9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};







typedef int (*key_callback)(int value);







int get_temperature_from_eeprom(int *min_temperature, int *max_temperature){



    char buf[3];

    int len;

    int ret = 0;



    pthread_mutex_lock(&mutex);



    buf[0] = DATA_ADDR;



    len = write(i2c_fd, buf, 1);

    if (len < 0) {

        printf("write data addr faile \n");

        ret = -1;

        goto out;

    }



    len = read(i2c_fd, buf, 3);

    if (len < 0) {

        printf("read data faile \n");

        ret = -1;goto out;

    }



    *min_temperature = (int)buf[0];

    *max_temperature = (int)buf[1];/* 如果在0x02地址没有读出0xAA表示EEPROM还没有写入最低/最高安全温度*/

    if (buf[2] != 0xAA) {

        ret = -2;

        goto out;

    }



out:



    pthread_mutex_unlock(&mutex);

    return ret;

}





int set_temperature_to_eeprom(int min_temperature, int max_temperature){

    char buf[4];

    int len;

    int ret = 0;



    pthread_mutex_lock(&mutex);



    buf[0] = DATA_ADDR;

    buf[1] = (char)min_temperature;

    buf[2] = (char)max_temperature;

    buf[3] = 0xAA;



    len = write(i2c_fd, buf, 4);

    if (len < 0) {

        printf("write data faile \n");

        ret = -1;

        goto out;

    }



    usleep(1000);



out:



    pthread_mutex_unlock(&mutex);

    return ret;



}

int  init_eeprom(void){

    int ret;

    int T1, T2;

    i2c_fd = open(I2C_DEV_NAME, O_RDWR);/* 打开I2C1总线设备*/

    if(i2c_fd < 0) {

        printf("open %s failed\r\n", I2C_DEV_NAME);

        return -1;

    }



    ret = ioctl(i2c_fd,I2C_SLAVE,I2C_ADDR>>1);

    if(ret<0){

        printf("setenv address faile ret:%x \n",ret );

        return -1;

    }





    ret= get_temperature_from_eeprom(&T1,&T2);

    if(ret == -1){

        printf("read data from eeprom faile at %s \n",__FUNCTION__);

        return -1;



    }else if(ret == -2){

        printf("init min & max temperature to eeprom \n");

        ret = set_temperature_to_eeprom(25,40);

        if(ret){

            printf("write date to eeprom faile at %s \n", __FUNCTION__);

        }

    }



    pthread_mutex_init(&mutex,NULL);

    return 0;

}





int init_temperature_function(void){

    if (access(ADC_DEV, F_OK)) {

        /* 检查ADC设备文件是否存在*/

        if (access(ADC_MODULE_PATH, F_OK) == 0) {

            /* 检查ADC模块是否存在*/

            system("insmod /root/lradc.ko");



            while (access(ADC_DEV, F_OK)) {

                /* 等待ADC设备文件生成完成*/

                sleep(1);

            }

        } else {

            printf("ADC module moust at /root/ \n");

            return -1;

        }

    }



    fd = open(ADC_DEV, 0);



    if(fd < 0){

        printf("open error by APP-%d\n",fd);

        return -1;

    }



    return 0;

}



double get_temperature(void){

    int adc_value;

    double voltage;

    double RT = 0;

    double  temp = 0;

    int ret;





        fd = open (LRADC_DEV,O_RDONLY);/* 打开ADC设备*/

    if (fd < 0) {

        perror("open");

        close(fd);

               return 0;

    }

    ret = ioctl(fd, IMX28_ADC_CH1, &adc_value);              /* 读取通道1的ADC原始值*/

    if (ret) {

        printf("get adc value faile \n");

        return -1;

    }



    voltage = (adc_value*1.85)/4096.0;/* 计算测量电压*/

    RT = (V_ADC/voltage -1)*R33;/* 计算热敏电阻的阻值*/

    temp = 3435/log(10*RT) -273.15;/* 计算热敏电阻的温度*/

    return temp;

}



static void show_led(int fd_spi, int fd_gpio, int value, int num)

{

    int ret;

    uint8_t tx[] = {

        led_value_table[value],

        (1 << num),

    };



    struct spi_ioc_transfer tr_txrx[] = {

        {

            .tx_buf      = (unsigned long)tx,

            .rx_buf      = 0,

            .len         = 2,

            .delay_usecs = delay,

            .speed_hz    = speed,

            .bits_per_word = bits,

        },

    };



    ret = ioctl(fd_spi, SPI_IOC_MESSAGE(1), &tr_txrx[0]);



    if (ret == 1) {

        printf("can't revieve spi message");

        return;

    }

    write(fd_gpio, "0", 1);

    usleep(100);

    write(fd_gpio, "1", 1);

}



 int show_led_num(int VALUE, int NUM)

{

    int ret       = 0;

    int fd_spi    = 0;

    int fd_gpio   = 0;

    int led_value = 0;

    int led_num   = 0;


    pthread_mutex_lock(&numlock);//----------------------------------------------hu 

    led_value = VALUE;/* 获取程序输入参数的数码管的显示值*/


    led_num = NUM;/* 获取程序输入参数的数字选择值*/


    fd_spi = open(SPI_DEVICE, O_RDWR);/* 打开SPI总线的设备文件*/

    if (fd_spi < 0) {

        printf("can't open --led_num-- %s \n", SPI_DEVICE);

        return -1;

    }



    fd_gpio = open(GPIO_DEVICE, O_RDWR);/* 打开GPIO设备的属性文件*/

    if (fd_gpio < 0) {

        printf("can't open %s device\n", GPIO_DEVICE);

        return -1;

    }



    ret = ioctl(fd_spi, SPI_IOC_WR_MODE, &mode);

    if (ret == -1) {

        printf("can't set wr spi mode\n");

        return -1;

    }



    ret = ioctl(fd_spi, SPI_IOC_WR_BITS_PER_WORD, &bits);/* 设置SPI的数据位*/

    if (ret == -1) {

        printf("can't set bits per word\n");

        return -1;

    }


    ret = ioctl(fd_spi, SPI_IOC_WR_MAX_SPEED_HZ, &speed);/* 设置SPI的最大总线频率*/

    if (ret == -1){

        printf("can't set max speed hz\n");

        return -1;

    }



    show_led(fd_spi, fd_gpio, led_value, led_num);



    close(fd_spi);

        close(fd_gpio);

        pthread_mutex_unlock(&numlock);



        return 0;



}


static int show_digitron(int *value){

    static int i = 0;

    //int show_value_led = 0;



    while ( 1 ) {



        if (is_show == DIGITRON_ON) {/* 当使能显示时*/



        /*把show_value数组中各元素的信息,显示在数码管相应的位段上*/



        show_led_num(show_value[i], i);



        } else {/* 当禁能显示时*/



            show_led_num(20, i);/* 在数码管的所有位段不显示任何信息*/



        }



        i++;



        if (i == 4) i = 0;



        usleep(1000);



        }

        return 0;

    }







int init_digitron(void){



    int ret;



    pthread_t thread_show;




    fd_spi = open(SPI_DEVICE, O_RDWR);/* 打开SPI总线设备文件*/



    if (fd_spi < 0) {



        printf("can not open %s \n", SPI_DEVICE);

        return -1;



    }



    ret = ioctl(fd_spi, SPI_IOC_WR_MODE, &mode);/* 设置SPI 总线的相位和极性*/

    if (ret == -1) {



        printf("can't set wr spi mode\n");

        return -1;



    }



    ret = ioctl(fd_spi, SPI_IOC_WR_BITS_PER_WORD, &bits);/* 设置SPI总线每字长度*/

    if (ret == -1) {



        printf("can't set bits per word\n");

        return -1;



    }



    ret = ioctl(fd_spi, SPI_IOC_WR_MAX_SPEED_HZ, &speed);/* 设置SPI总线最高速率*/

    if (ret == -1){



        printf("can't set max speed hz\n");

        return -1;



    }



    fd_gpio = open(GPIO_DEVICE, O_RDWR);/* 打开GPIO的设备属性文件*/

    if (fd_gpio < 0) {



        printf("can't open %s device\n", GPIO_DEVICE);

        return -1;



    }



    /* 启动线程*/

    ret = pthread_create(&thread_show, PTHREAD_CREATE_JOINABLE, (void *)show_digitron, NULL);

    if (ret) {

        printf("create thread faile \n");

        return -1;

    }



    return 0;

}





void set_digitron_value(int value1, int value2, int value3, int value4){



    show_value[0] = value1;

    show_value[1] = value2 + 10;/* 在个位加上小数点*/

    show_value[2] = value3;

    show_value[3] = value4;



    }





void set_digitron_on(int value){

    is_show = value;

    }





static key_callback key_callback_fun[5] = {NULL, NULL, NULL, NULL, NULL};



int install_key_function(key_callback p, int key)/* 注册回调函数*/{

    if (p == NULL) {



        return -1;



    }



    if (key_callback_fun[key]) {

        /* 防止多次设置*/

        return -1;



    } else {



        key_callback_fun[key] = p;



    }



    return 0;

}





enum{

    KEY1,



    KEY2,



    KEY3,



    KEY4,



    KEY5

}; 





static int key_pthread(void){



    int count;



    struct input_event input_event_value;



    while(1) {



        count=read(fd, &input_event_value, sizeof(struct input_event));/* 监视按键输入事件*/



        if (count < 0) {printf("read iput device event error \n");

        return -1;

        }



        /* 判断是哪个键被按下/提起*/

        switch (input_event_value.code) {



            case KEY_A:/* KEY1按键*/

                if (key_callback_fun[KEY1]) {



                    key_callback_fun[KEY1](input_event_value.value);



                }

                break;



            case KEY_B:/* KEY2按键*/

                if (key_callback_fun[KEY2]) {



                    key_callback_fun[KEY2](input_event_value.value);



                }

                break;



            case KEY_C:/* KEY3按键*/

                if (key_callback_fun[KEY3]) {



                    key_callback_fun[KEY3](input_event_value.value);



                }

                break;



            case KEY_D:/* KEY4按键*/

                if (key_callback_fun[KEY4]) {



                    key_callback_fun[KEY4](input_event_value.value);



                }

                break;



            case KEY_E:/* KEY5按键*/

                if (key_callback_fun[KEY5]) {



                    key_callback_fun[KEY5](input_event_value.value);



                }

                break;



            default:

                break;



        }

    }

    return 0;

}



int init_event_key(void){



    int ret;



    pthread_t thread_key;



    if (access(DEV_NAME, F_OK)) {   /* 检查按键设备文件是否存在*/



        if (access(KEY_MODULE_PATH, F_OK) == 0) {/* 检查按键模块是否存在*/



            system("insmod /root/imx_key.ko");



            while (access(DEV_NAME, F_OK)) {/* 等待按键设备文件生成*/

                sleep(1);

            }

        } else {



            printf("key module moust at /root \n");

            return -1;



        }

    }



    fd = open (DEV_NAME, O_RDWR);

    if (fd < 0) {



        perror(DEV_NAME);

        exit(0);



    }/* start key conctol pthread */



    ret = pthread_create(&thread_key, PTHREAD_CREATE_JOINABLE, (void *)key_pthread, NULL);

    if (ret) {



        printf("create thread faile at %s \n", __FUNCTION__);

        return -1;

    }



    return 0;

}





static enum {



    SHOW_L,

    SHOW_H, /* 显示最高安全温度状态 */

    SHOW_TEMPER,



} sys_status;





static int key2_action(int value){/* 只响应键按下事件,忽略键提起事件*/



    if (value == 0) {



        return 0;

    }



    sys_status = SHOW_L;/* 设置为显示最低安全温度状态*/



    return 0;

}





static int key3_action(int value){/* 只响应键按下事件,忽略键提起事件*/



    if (value == 0) {

        return 0;

    }



    sys_status = SHOW_TEMPER;/* 设置为显示当前环境温度状态*/



    return 0;

}





static int key4_action(int value){/* 只响应键按下事件,忽略键提起事件*/



    if (value == 0) {



        return 0;



    }



    sys_status = SHOW_H;/* 设置为显示最高安全温度状态*/



    return 0;



}



static int key1_action(int value){



    int min_temperature = 0, max_temperature = 0;

    int ret;/* 只响应键按下事件,忽略键提起事件*/



    if (value == 0) {



        return 0;



    }



    /* 在EEPROM读出最高/最低安全温度值*/

    ret = get_temperature_from_eeprom(&min_temperature, &max_temperature);

    if (ret) {



        printf("get temperature from eeprom faile at %s \n", __FUNCTION__);

        return -1;



    }



    switch (sys_status) {



        case SHOW_L:/* 若当处于显示最低安全温度状*/

            if (min_temperature > 0) {/* 最低安全温度不能小于0*/

                min_temperature--;

            }

            break;



        case SHOW_H:/* 当处于显示最高安全温度状态*//* 最高安全温度不能低于最低安全温度*/

            if (max_temperature > min_temperature) {

                max_temperature--;

            }   

            break;



        case SHOW_TEMPER:



            break;

        }



    /* 在EEPROM写入最低/最安全高温度值*/

    ret = set_temperature_to_eeprom(min_temperature, max_temperature);

    if (ret) {



        printf("set temperature to eeprom faile at %s \n", __FUNCTION__);

        return -1;



    }



    return 0;

}





static int key5_action(int value){



    int min_temperature = 0, max_temperature = 0;

    int ret;/* 只响应键按下事件,忽略键提起事件*/



    if (value == 0) {



        return 0;



    }



    /* 在EEPROM读出最高/最低安全温度值*/

    ret = get_temperature_from_eeprom(&min_temperature, &max_temperature);

    if (ret) {



        printf("get temperature from eeprom faile at %s \n", __FUNCTION__);

        return -1;



    }



    switch (sys_status) {



        case SHOW_L:/* 若当处于显示最低安全温度状*//* 最低安全温度不能高于最高安全温度*/

            if (min_temperature < max_temperature){

                min_temperature++;

            }

            break;



        case SHOW_H:/* 当处于显示最高安全温度状态*/

            if (max_temperature < 85) {/* 最高安全温度不能高于85度*/

            max_temperature++;

            }

            break;



        case SHOW_TEMPER:



            break;

    }


    /* 在EEPROM写入最低/最高安全温度值*/

    ret = set_temperature_to_eeprom(min_temperature, max_temperature);

    if (ret) {



        printf("set temperature to eeprom faile at %s \n", __FUNCTION__);

        return -1;



    }



    return 0;



}



void set_digitron_vlue(int value1,int value2,int value3,int value4)

{


    show_value[0]=value1;

    show_value[1]=value2;

    show_value[2]=value3;

    show_value[3]=value4;



}


int beep_on(void)

{

    //int ret;



    //ret = write(BEEP_DEV, 1,1);



    //if(ret < 0) { 



        //perror("beep on");



    //}

return 0;



}



int beep_off(void)

{

    //int ret;



    //ret = write(BEEP_DEV, 0,1);



    //if(ret < 0) { 



        //perror("beep off");



    //}

return 0;



}



static int thread_control(int *value){


    int min_temperature = 0, max_temperature = 0, temperature;

    float temp_t;

    int ret = -1;

    int value1, value2, value3,value4;



    while (1) {



        /* 在EEPROM读取最低/最高安全温度值*/

        ret = get_temperature_from_eeprom(&min_temperature,&max_temperature);

        if (ret) {



            printf("read temperature faile \n");

            break;



        }



        temp_t = get_temperature();/* 获取当前环境温度*/

        temperature = (int )(temp_t * 100.0);/* 获取当前环境温度并转换为整数*/



        /* 显示控制*/

        switch (sys_status) {



            /* 当处于显示最低安全温度状态时,数码管显示类似:26.0L */

            case SHOW_L:

                value1 = min_temperature / 10;/* 数码管1位段显示最低安全温度的十位*/

                value2 = min_temperature % 10;/* 数码管2位段显示最低安全温度的个位*/

                value3 = 0;/* 数码管3位段显示0*/

                value4 = 22;/* 数码管4位段显示"L"*/

                set_digitron_vlue(value1, value2, value3, value4);

                break;



            /* 当处于显示最高安全温度状态时,数码管显示类似:40.0H */  

            case SHOW_H:

                value1 = max_temperature / 10;/* 数码管1位段显示最高安全温度的十位*/

                value2 = max_temperature % 10;/* 数码管2位段显示最高安全温度的个位*/

                value3 = 0;/* 数码管3位段显示显示0*/

                value4 = 21;/* 数码管4位段显示"H"*/

                set_digitron_vlue(value1, value2, value3, value4);

                break;



            /* 显示当前环境温度:两位整数,两位小数*/

            case SHOW_TEMPER:/* 注意temperature已经把当前环境温度值乘以100,转换成整数值*/

                value1 = temperature/1000;/* 数码管的1位段显示当前环境温度的十位*/

                value1 = value1%10;

                value2 = temperature/100;/* 数码管的2位段显示当前环境温度的个位*/

                value2 = value2%10;

                value3 = temperature/10;/*数码管的3位段显示当前环境温度的十分位*/

                value3 = value3%10;

                value4 = temperature%10;/*数码管的4位段显示当前环境温度的百分位*/

                set_digitron_vlue(value1, value2, value3, value4);

                break;



            default:



                break;

        }



        /* 监控当前环境温度*/

        if (temp_t < min_temperature) { /* 温度过低*/

        /* 蜂鸣器短鸣一声,数码管显示的数字闪烁*/     

            beep_on();

            set_digitron_on(DIGITRON_OFF);



            usleep(50*1000);

            set_digitron_on(DIGITRON_ON);

            beep_off();


        } else if (temp_t > max_temperature) {/* 温度过高*/

        /* 蜂鸣器短鸣两声,数码管显示的数字闪烁*/

            beep_on();

            set_digitron_on(DIGITRON_OFF);

            usleep(50*1000);

            set_digitron_on(DIGITRON_ON);

            beep_off();



            usleep(20*1000);

            beep_on();



            usleep(50*1000);

            beep_off();

        }



        usleep(300*1000);

    }

     return NULL;

}


int init_control(void){



    int ret;



    pthread_t thread_control_t;



    sys_status = SHOW_TEMPER;/*初始化为显示当前环境温度状态*/



    beep_fd = open(BEEP_DEV, O_RDWR);/* 打开蜂鸣器设备属性文件*/



    if(beep_fd < 0) { 



        perror("open beep device");



    }



    ret = install_key_function(key1_action, KEY1);/* 在KEY1按键安装响应函数*/

    if (ret) {



        printf("install call fun faile in %s \n", __FUNCTION__);

        return -1;



    }



    ret = install_key_function(key2_action, KEY2);/* 在KEY2按键安装响应函数*/

    if (ret) {



        printf("install call fun faile in %s \n", __FUNCTION__);

        return -1;



    }



    ret = install_key_function(key3_action, KEY3);/* 在KEY3按键安装响应函数*/

    if (ret) {



        printf("install call fun faile in %s \n", __FUNCTION__);

        return -1;

    }



    ret = install_key_function(key4_action, KEY4);/* 在KEY4按键安装响应函数*/

    if (ret) {



        printf("install call fun faile in %s \n", __FUNCTION__);

        return -1;

    }



    ret = install_key_function(key5_action, KEY5);/* 在KEY5按键安装响应函数*/

    if (ret) {printf("install call fun faile in %s \n", __FUNCTION__);



        return -1;

    }



    /* 生成温度监控线程*/

    ret = pthread_create(&thread_control_t, PTHREAD_CREATE_JOINABLE, (void *)thread_control, NULL);

    if (ret) {



        printf("create thread faile in %s \n", __FUNCTION__);

        return -1;



    }



    return 0;

}





int main(int argc, char *argv[]){



    int ret;

    //int fd;

    //double value;



    ret = init_digitron();/* 初始化数码管模块*/

    if (ret)

        return -1;



    ret = init_eeprom();/* 初始化eeprom模块*/

    if (ret)

        return -1;



    ret = init_temperature_function();/* 初始化温度读取模块*/

    if (ret)  

        return -1;



    ret = init_event_key();/* 初始化按键模块*/

    if (ret) 

        return -1;



    ret = init_control();/* 初始化监控模块*/

    if (ret) 

        return -1;



    while ( 1 ) {



        sleep(1);

    }



    return ret;

}



显示效果图:


![这里写图片描述](https://img-blog.csdn.net/20180727093803200?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpYm94aXU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)








猜你喜欢

转载自blog.csdn.net/liboxiu/article/details/81231669