Read DS18B20 Temperature via Mapping Memory Method in Linux
2017-08-28 16:54
731 查看
In the website, there are lots code to demonstrate how to set and fetch the temperature data measured by ds18b20, but Most are drive-based, some are UART-base; there are only a few code fetching data via mapping memory method.
Basically, programmer should avoid to insert driver as possible as he can, for driver within defect may entail whole system would not work or be disordered. Accessing mapped memory is a much better solution from my perspective.
This post is to complement my
previous article, to demonstrate another example of
how to manipulate GPIO for transmission of data via mapped memory.
DS18B20 is a good digitall temperature measurer featuring its high precision from -10 ~ 85 degree, and supporting multi-sensor on one wire(GPIO). And it is very easy to buy a DS18B20 in cable form, which is very useful to measure the temperature of liquid.
For DS18B20 is pull-up based voltage, you need to connect Vcc pin to Data pin with a resistor in middle value (2k Ohm- 10k, 4.7k is the most typical),even you use the water-proof one.
My code for GPIO is based on Atheros AR9330@MIPS, if your CPU is not the same as mine, you need to re-implement the GPIO manipulation functions.
The code be :
The makefile is just to adopt cross(parasitic)-compiler to build the code:
Run the binary:
The first argument is the GPIO connected with DS18B20 sensor, the second one is reslution, which is to specify how many bit for describing the temperature, from 9 to 12.
The measured temperatures need to be compensated 10 degree, for the weather is impossible so hot in Taiwan even it is the beginning of autumn.
Basically, programmer should avoid to insert driver as possible as he can, for driver within defect may entail whole system would not work or be disordered. Accessing mapped memory is a much better solution from my perspective.
This post is to complement my
previous article, to demonstrate another example of
how to manipulate GPIO for transmission of data via mapped memory.
DS18B20 is a good digitall temperature measurer featuring its high precision from -10 ~ 85 degree, and supporting multi-sensor on one wire(GPIO). And it is very easy to buy a DS18B20 in cable form, which is very useful to measure the temperature of liquid.
For DS18B20 is pull-up based voltage, you need to connect Vcc pin to Data pin with a resistor in middle value (2k Ohm- 10k, 4.7k is the most typical),even you use the water-proof one.
My code for GPIO is based on Atheros AR9330@MIPS, if your CPU is not the same as mine, you need to re-implement the GPIO manipulation functions.
The code be :
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <signal.h> #include <sys/time.h> #include <sys/mman.h> #include <fcntl.h> #include <errno.h> #define GPIO_ADDR (0x18040000) #define GPIO_MEM_BLOCK_SIZE (48) int MappingGPIOToMemory(unsigned long **pp_gpio_address) { int mem_fd; if ((mem_fd = open("/dev/mem", O_RDWR)) < 0) { printf("Open /dev/mem fail\r\n"); return -1; }/*if */ *pp_gpio_address = (unsigned long*)mmap(NULL, GPIO_MEM_BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, GPIO_ADDR); close(mem_fd); if (*pp_gpio_address == MAP_FAILED) { printf("mapping memory fail\r\n"); printf("error message = %s\r\n", strerror(errno)); return -2; } }/*MappingGPIOToMemory*/ #define PIN_OUT (1) #define PIN_IN (0) void SetGPIODirection(unsigned long *p_gpio_address, int gpio_numer, int direction) { #define GPIO_OUTPUT_ENABLE_OFFSET (0) unsigned long value; value = *(p_gpio_address + GPIO_OUTPUT_ENABLE_OFFSET); if (PIN_IN == direction) value &= ~(1 << gpio_numer); else value |= (1 << gpio_numer); *(p_gpio_address + GPIO_OUTPUT_ENABLE_OFFSET) = value; }/*SetGPIODirection*/ #define HIGH (1) #define LOW (0) void SetGPIOValue(unsigned long *p_gpio_address, int gpio_numer, int value) { #if(1) #define GPIO_OUT_VALUE_OFFSET (2) unsigned long full_register_value; full_register_value = *(p_gpio_address + GPIO_OUT_VALUE_OFFSET); if (0 == value) full_register_value &= ~(1 << gpio_numer); else full_register_value |= (1 << gpio_numer); *(p_gpio_address + GPIO_OUT_VALUE_OFFSET) = full_register_value; #else #define GPIO_SET_OFFSET (3) #define GPIO_CLEAR_OFFSET (4) if(0 == value) *(p_gpio_address + GPIO_CLEAR_OFFSET) = (1 << gpio_numer); else *(p_gpio_address + GPIO_SET_OFFSET) = (1 << gpio_numer); #endif }/*SetGPIOValue*/ void GetGPIOValue(unsigned long *p_gpio_address, int gpio_numer, int *p_value) { #define GPIO_INPUT_VALUE_OFFSET (1) unsigned long full_register_value; full_register_value = *(p_gpio_address + GPIO_INPUT_VALUE_OFFSET); *p_value = (full_register_value >> gpio_numer) & 0x01; }/*GetGPIOValue*/ void delay_micro_sec(unsigned int delay_time_in_us) { struct timeval now; struct timeval period; struct timeval end; gettimeofday(&now, NULL); period.tv_sec = delay_time_in_us / 1000000; period.tv_usec = delay_time_in_us % 1000000; timeradd(&now, &period, &end); while(timercmp(&now, &end, < )) gettimeofday(&now, NULL); }/*delay_micro_sec*/ enum DS18B20_Resolution { DS18B20_9_Bit_Resolution = 0, DS18B20_10_Bit_Resolution = 1, DS18B20_11_Bit_Resolution = 2, DS18B20_12_Bit_Resolution = 3, } ; int ResetDS18B20(unsigned long *p_gpio_address, int gpio_numer) { unsigned int time_cnt; SetGPIODirection(p_gpio_address, gpio_numer, PIN_OUT); //SetGPIOValue(p_gpio_address, gpio_numer, HIGH); //delay_micro_sec(2); #define RESET_DS18B20_PULL_DOWN_TIME_IN_USEC (600) SetGPIOValue(p_gpio_address, gpio_numer, LOW); delay_micro_sec(RESET_DS18B20_PULL_DOWN_TIME_IN_USEC); SetGPIODirection(p_gpio_address, gpio_numer, PIN_IN); #define DS18B20_RESISTOR_PULL_UP_IN_USEC (60) time_cnt = 0; while(1) { int pin_value; GetGPIOValue(p_gpio_address, gpio_numer, &pin_value); delay_micro_sec(1); if(LOW == pin_value) break; if(DS18B20_RESISTOR_PULL_UP_IN_USEC == time_cnt) break; time_cnt++; }/*while high*/ if(DS18B20_RESISTOR_PULL_UP_IN_USEC == time_cnt) { printf("RESTIOR_PULL_UP_ERROR\r\n"); return -1; }/*over time*/ #define DS18B20_RESP_PULL_DOWN_IN_USEC (240) time_cnt = 0; while(1) { int pin_value; GetGPIOValue(p_gpio_address, gpio_numer, &pin_value); delay_micro_sec(1); if(HIGH == pin_value) break; if(DS18B20_RESP_PULL_DOWN_IN_USEC == time_cnt) break; time_cnt++; }/*while low*/ if(DS18B20_RESP_PULL_DOWN_IN_USEC == time_cnt) { printf("DS18B20_RESP_PULL_DOWN\r\n"); return -2; }/*over time*/ #define DS18B20_RESP_TOTAL_TIME_IN_USEC (480) delay_micro_sec(DS18B20_RESP_TOTAL_TIME_IN_USEC - time_cnt); return 0; }/*ResetDS18B20*/ int ReadDS18B20Byte(unsigned long *p_gpio_address, int gpio_numer, unsigned char *p_datum) { int i; unsigned char datum; int one_bit_value; datum = 0; for(i = 0; i < 8; i++){ SetGPIODirection(p_gpio_address, gpio_numer, PIN_OUT); SetGPIOValue(p_gpio_address, gpio_numer, LOW); #define DS18B20_MASTER_PULL_DOWN_TIME_FOR_READ_IN_USEC (2) delay_micro_sec(DS18B20_MASTER_PULL_DOWN_TIME_FOR_READ_IN_USEC); SetGPIODirection(p_gpio_address, gpio_numer, PIN_IN); #define DS18B20_RECOVER_TIME_AFTER_PULL_DOWN_FOR_READ_IN_USEC (5) delay_micro_sec(DS18B20_RECOVER_TIME_AFTER_PULL_DOWN_FOR_READ_IN_USEC); GetGPIOValue(p_gpio_address, gpio_numer, &one_bit_value); datum |= (one_bit_value << i); #define DS18B20_ONE_BIT_READ_TIME_IN_USEC (62) delay_micro_sec(DS18B20_ONE_BIT_READ_TIME_IN_USEC - DS18B20_RECOVER_TIME_AFTER_PULL_DOWN_FOR_READ_IN_USEC - DS18B20_MASTER_PULL_DOWN_TIME_FOR_READ_IN_USEC); }/*for one byte*/ //SetGPIODirection(p_gpio_address, gpio_numer, PIN_IN); *p_datum = datum; return 0; }/*ReadDS18B20Byte*/ int WriteDS18B20Byte(unsigned long *p_gpio_address, int gpio_numer, unsigned char data) { int i; SetGPIODirection(p_gpio_address, gpio_numer, PIN_OUT); for(i = 0; i < 8; i++){ #define DS18B20_RECOVER_TIME_FOR_INDIVIDUAL_SLOT_WRITE_IN_USEC (2) SetGPIOValue(p_gpio_address, gpio_numer, LOW); delay_micro_sec(DS18B20_RECOVER_TIME_FOR_INDIVIDUAL_SLOT_WRITE_IN_USEC); #define DS18B20_ONE_BIT_WRITE_TIME_IN_USEC (60) if(0x01 & data) SetGPIOValue(p_gpio_address, gpio_numer, HIGH); else SetGPIOValue(p_gpio_address, gpio_numer, LOW); delay_micro_sec(DS18B20_ONE_BIT_WRITE_TIME_IN_USEC - DS18B20_RECOVER_TIME_FOR_INDIVIDUAL_SLOT_WRITE_IN_USEC); data >>= 1; #define DS18B20_ONE_BIT_WRITE_END_PULL_UP_TIME_IN_USEC (1) SetGPIOValue(p_gpio_address, gpio_numer, HIGH); delay_micro_sec(DS18B20_ONE_BIT_WRITE_END_PULL_UP_TIME_IN_USEC); }/*for 8 bit*/ //SetGPIODirection(p_gpio_address, gpio_numer, PIN_IN); return 0; }/*WriteDS18B20Byte*/ int WriteDS18B20Command(unsigned long *p_gpio_address, int gpio_numer, unsigned char command_code) { return WriteDS18B20Byte(p_gpio_address, gpio_numer, command_code); }/*SendDS18B20Command*/ int WaitDS18B20TemperatureConvertingDone(unsigned long *p_gpio_address, int gpio_numer, enum DS18B20_Resolution resolution) { unsigned int time_cnt; unsigned int max_duration_time_in_msec; #define DS18B20_MIN_CONVERT_TIME_IN_MSEC (750/8) #define BUFFER_TIME (100/8) max_duration_time_in_msec = (1 >> resolution)*(DS18B20_MIN_CONVERT_TIME_IN_MSEC + BUFFER_TIME); SetGPIODirection(p_gpio_address, gpio_numer, PIN_IN); delay_micro_sec(1); while(1) { int pin_value; GetGPIOValue(p_gpio_address, gpio_numer, &pin_value); delay_micro_sec(1); if(1 == pin_value) break; if(max_duration_time_in_msec == time_cnt) break; time_cnt++; }/*while 1*/ if(max_duration_time_in_msec == time_cnt) { printf("Convert fail\r\n"); return -1; } return 0; }/*WaitDS18B20TemperatureConvertingDone*/ unsigned char CRCiButtonUpdate(unsigned char crc, unsigned char data) { int i; crc = crc ^ data; #define CRC_POLY (0x8C) for(i = 0; i < 8; i++){ if (crc & 0x01) crc = (crc >> 1) ^ CRC_POLY; else crc >>= 1; }/*for i*/ return crc; }/*CRCiButtonUpdate*/ #define SKIP_DS18B20_ROM (0xCC) #define CONVERT_DS18B20_TEMP (0x44) #define WRITE_DS18B20_RAM (0x4E) #define READ_DS18B20_RAM (0xBE) int SetDS18B20Resolution(unsigned long *p_gpio_address, int gpio_numer, enum DS18B20_Resolution resolution) { if(0 != ResetDS18B20(p_gpio_address, gpio_numer)) { printf("ResetDS18B20 error in %s\r\n", __func__); return -1; }/*avoid the reseting does not be called in the begin*/ WriteDS18B20Command(p_gpio_address, gpio_numer, SKIP_DS18B20_ROM); WriteDS18B20Command(p_gpio_address, gpio_numer, WRITE_DS18B20_RAM); { #define DS18B20_MINUS_SIGN(VALUE) ((0x1<<7)|(VALUE)) WriteDS18B20Byte(p_gpio_address, gpio_numer, 100); WriteDS18B20Byte(p_gpio_address, gpio_numer, DS18B20_MINUS_SIGN(55)); }/*useless block to fill the head 2 bytes of write ram */ WriteDS18B20Byte(p_gpio_address, gpio_numer, ((0x03 & resolution) << 5) | 0x1f ); if(0 != ResetDS18B20(p_gpio_address, gpio_numer)) { printf("%s error\r\n", __func__); return -1; }/*if ResetDS18B20 error*/ return 0; }/*SetDS18B20Resolution*/ int ReadDS18B20Temperature(unsigned long *p_gpio_address, int gpio_numer, enum DS18B20_Resolution resolution, float *p_temperature) { if(0 != ResetDS18B20(p_gpio_address, gpio_numer)) { printf("ResetDS18B20 1st error\r\n"); return -1; } SetDS18B20Resolution(p_gpio_address, gpio_numer, resolution); WriteDS18B20Command(p_gpio_address, gpio_numer, SKIP_DS18B20_ROM); WriteDS18B20Command(p_gpio_address, gpio_numer, CONVERT_DS18B20_TEMP); if(0 != WaitDS18B20TemperatureConvertingDone(p_gpio_address, gpio_numer, resolution)) { return -3; printf("Temperature converting error\r\n"); } if(0 != ResetDS18B20(p_gpio_address, gpio_numer)) { printf("ResetDS18B20 3nd error\r\n"); return -4; } WriteDS18B20Command(p_gpio_address, gpio_numer, SKIP_DS18B20_ROM); WriteDS18B20Command(p_gpio_address, gpio_numer, READ_DS18B20_RAM); { short temperature; unsigned char raw_temperature[2]; int i; unsigned char byte_datum; unsigned char computed_crc, read_crc; computed_crc = 0x00; for(i = 0; i< 8; i++){ ReadDS18B20Byte(p_gpio_address, gpio_numer, &byte_datum); computed_crc = CRCiButtonUpdate(computed_crc, byte_datum); if(0 == i) raw_temperature[0] = byte_datum; if(1 == i) raw_temperature[1] = byte_datum; }/*for i */ ReadDS18B20Byte(p_gpio_address, gpio_numer, &read_crc); if(read_crc != computed_crc) { //printf("read_crc = %d, computed_crc = %d\r\n", // read_crc, computed_crc); return -4; } raw_temperature[0] >>= (3 - resolution); raw_temperature[0] <<= (3 - resolution); temperature = raw_temperature[0] + (raw_temperature[1] << 8); #if(0) if(0x01 & (temperature >> 11)) temperature = -1* (0x07ff & temperature); #else temperature = ((temperature >> 11) | 0x01) * (0x07ff & temperature); #endif *p_temperature = temperature/16.0; } return 0; }/*ReadDS18B20*/ unsigned long *p_gpio_address = NULL; void InterruptSignalHandlingRoutine(int sig) { if(NULL != p_gpio_address) munmap(p_gpio_address, GPIO_MEM_BLOCK_SIZE); p_gpio_address = NULL; exit(0); }/*InterruptSignalHandlingRoutine*/ void print_current_time(void) { time_t t; struct tm calendar_time; t = time(NULL); localtime_r(&t, &calendar_time); printf("now time: %d-%d-%d %d:%d:%d, %s(+%d)\n", calendar_time.tm_year + 1900, calendar_time.tm_mon + 1, calendar_time.tm_mday, calendar_time.tm_hour, calendar_time.tm_min, calendar_time.tm_sec, calendar_time.tm_zone, (int)calendar_time.tm_gmtoff/3600); }/*print_current_time*/ int main(int argc, char *argv[]) { float temperature; int executed_count; int succeeded_count; int g_gpio_number; int resolution; resolution = DS18B20_12_Bit_Resolution; signal(SIGINT, InterruptSignalHandlingRoutine); if(2 > argc) { printf("%s should be followed by led_gpio_pin_number\r\n", argv[0]); return -1; } //if(1 < argc) { char *p_temp; g_gpio_number = strtol(argv[1], &p_temp, 10); if(argv[1]== p_temp || g_gpio_number < 0) { printf("%s is not a number for specifying gpio pin number\r\n", argv[1]); return -2; }/*not a number*/ }/*local variable*/ if(2 < argc) { char *p_temp; resolution = strtol(argv[2], &p_temp, 10); if(argv[2]== p_temp) { printf("%s is not a number to specify resolution\r\n", argv[2]); return -3; }/*not a number*/ if(resolution > 12 || resolution < 9) { printf("%s should be >= 9 and <= 12 \r\n", argv[2]); return -3; } }/*local variable*/ MappingGPIOToMemory(&p_gpio_address); while(1) { if(0 == ReadDS18B20Temperature(p_gpio_address, g_gpio_number, (enum DS18B20_Resolution)(resolution - 9), &temperature)) { printf("temperature = %7.4f\r\n\r\n", temperature); print_current_time(); usleep(3*1000*1000); } } if(NULL != p_gpio_address) munmap(p_gpio_address, GPIO_MEM_BLOCK_SIZE); p_gpio_address = NULL; return 0; }/*main*/
The makefile is just to adopt cross(parasitic)-compiler to build the code:
OPENWRT_ROOT=/home/openwrt-cc/staging_dir OPENWRT_TOOLCHAIN_PATH = $(OPENWRT_ROOT)/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2 CC = $(OPENWRT_TOOLCHAIN_PATH)/bin/mips-openwrt-linux-gcc CFLAGS := -O2 all: $(CC) $(CFLAGS) main.c -o ds18b20_temperature clean: rm ds18b20_temperature -f
Run the binary:
The first argument is the GPIO connected with DS18B20 sensor, the second one is reslution, which is to specify how many bit for describing the temperature, from 9 to 12.
root@GL-AR150:/tmp# ./ds18b20_temperature 26 9 #gpio = 20, reslution = 9(to 1/2) temperature = 32.0000 now time: 2017-8-28 15:33:20, CST(+8) temperature = 31.5000 now time: 2017-8-28 15:33:23, CST(+8) temperature = 32.0000
root@GL-AR150:/tmp# ./ds18b20_temperature 26 12 #gpio = 20, resolution = 12(to 2^-4 =0.0625) temperature = 31.2500 now time: 2017-8-28 15:36:49, CST(+8) temperature = 31.3125 now time: 2017-8-28 15:36:52, CST(+8) temperature = 31.3750 now time: 2017-8-28 15:36:55, CST(+8) temperature = 31.2500 now time: 2017-8-28 15:36:58, CST(+8) temperature = 31.3750 now time: 2017-8-28 15:37:1, CST(+8) temperature = 31.4375
The measured temperatures need to be compensated 10 degree, for the weather is impossible so hot in Taiwan even it is the beginning of autumn.
相关文章推荐
- [Ubuntu] Simple method to login SSH without insert user name and password via expect in linux
- Linux Device Drivers 3rd Edition Memory Mapping and DMA
- SHELL:Find Memory Usage In Linux (统计每个程序内存使用情况)
- A log about Reading the memroy of Other Process in C++/WIN API--ReadProcessMemory()
- Local File Read via XSS in Dynamically Generated PDF
- Linux GPIO Manipulation via Accessing Mapped Physical Memory
- MemoryMappedFile 在 Mono in Linux 的开发笔记
- High Memory in the Linux Kernel
- Feature: High Memory In The Linux Kernel
- How to read Mac .DMG file in Linux or PC(II)
- PatentTips - Method to manage memory in a platform with virtual machines
- Linux Memory Mapping
- Uncontrolled memory mapping in camera driver (CVE-2013-2595)
- MemoryMappedFile 在 Mono in Linux 的开发笔记
- Strange patent filed in China: Method to boot Linux OS from mobile harddisk
- Feature: High Memory In The Linux Kernel
- Measuring memory in Linux (the basics)
- 【读书笔记】ndss2018_K-Miner_ Uncovering Memory Corruption in Linux
- Java Read CSV File In Java With OpenCSV library 以及中文件乱码解决, Mapping CSV with Java beans
- zz Release memory in Linux (Unused or Cached)