Hello everyone. I am using the board SAM R34 Xplained Pro and sensor ds18b20. For this to work and read the temperature I need to create a oneWire library to use the sensor, and I think I am almost there, but I cannot seem to make it work. The code I have written is using asf.h, and is thought for the particular case of: the ds18b20 with External Supply, only one sensor and an external pullup of 4.7KΩ. I guess I could make the pin pullup and retrieve the external one, but I am sticking to the documentation.
The error I am facing is that the reading pin is getting the value 1 constantly, and so every byte read is 255, which is not correct. Here is a picture of my connection. I am using Pin PA06 for the data pin:
I have tried this same wiring using an Mega2560 and I am able to read using the arduino libraries, so it is not a sensor issue.
Also, I have based myself on some code on other discussions, but I have not find one that could make me realize my error, so I apologize if there is, I am pretty new to all this.
I attach the code of both the .h and .c
This is the code for my oneWire.h:
#ifndef _oneWire_H #define _oneWire_H #include "asf.h" /**********************************************************************/ //ONEWIRE --> TEMPERATURE SENSOR DS18B20 //Note: //The code is implemented to: // -Power the DS18B20 with an External supply // -Only one sensor // -External 4.7K PullUp resistance /**********************************************************************/ /**********************************************************************/ //DS18B20 TEMPERATURE SENSOR - COMMAND DESCRIPTION /**********************************************************************/ #define CONVER_TEMP 0x44 #define READ_SCRATCH 0xBE #define SKIP_ROM 0xCC #define READ_ROM 0x33 /**********************************************************************/ //PIN DEFINITION /**********************************************************************/ #define PIN_ONEWIRE PIN_PA06 #define INPUT PORT_PIN_DIR_INPUT #define OUTPUT PORT_PIN_DIR_OUTPUT #define PULL_SETTING PORT_PIN_PULL_NONE /**********************************************************************/ // DECLARATION OF FUNCTIONS /**********************************************************************/ //Function to initialize GPIO (pin P0.31) void initOneWire (void); //read from pin unsigned char read_pin(void); //This function is required for starting all the communications /*All communication with the DS18B20 begins with an initialization sequence that consists of a reset pulse from the master followed by a presence pulse from the DS18B20. When the DS18B20 sends the presence pulse in response to the reset, it is indicating to the master that it is on the bus and ready to operate.*/ uint8_t resetWire(void); //Send command to convert temp and read temperature data in Celsius float OnewireReadTemp(void); void OnewireSendConvertTempCommand(void); //only send command to convert temp float OnewireReceivedTemp(void); //only received temp (necessary to send command previously) //This funciton is internally used by OneWireReadTemp() function. //The temperature data is stored as a 16-bit sign-extended two's complement number in the temperature register. If the //DS18B20 is configured for 12-bit resolution (by default), all bits in the temperature register will contain valid data float complement2_12bitsResolution (uint16_t); //put gpio pin as an input void goInput(void); //put gpio pin as an out void goOutput(void); //send command void SendCMD(uint8_t); //read data int ReadBit(void); int ReadByte(void); //this functions are not used //not sure if they work properly void ReadSerialNumber(void); int iBSPACMonewireComputeCRC (const unsigned char *, int); #endif
Here the oneWire.c:
#include "oneWire.h" #include "string.h" struct port_config pin_conf; void initOneWire(void) { //Init GPIO for communication //I don´t know if I should try this //PORT->Group[0].PINCFG[PIN_ONEWIRE].bit.DRVSTR = PORT_PINCFG_DRVSTR_Pos; //PORT->Group[0].PINCFG[PIN_ONEWIRE].bit.PULLEN = PORT_PINCFG_PULLEN_Pos; //PORT->Group[0].PINCFG[PIN_ONEWIRE].bit.INEN = PORT_PINCFG_INEN_Pos; //PORT->Group[0].DIRSET.bit.DIRSET = (1 << PIN_ONEWIRE); //Init GPIO for communication port_get_config_defaults(&pin_conf); pin_conf.input_pull = PULL_SETTING; pin_conf.direction = INPUT; port_pin_set_config(PIN_ONEWIRE, &pin_conf); OnewireSendConvertTempCommand(); } unsigned char read_pin(void){ unsigned char read_data = 0; // variable for status of pin, 8 bits // Make Probe_Pin an input by putting 1 on TRIS //read_data = PORT->Group[0].IN.bit.IN & (1<<PIN_ONEWIRE); port_pin_get_input_level(PIN_ONEWIRE); return (read_data); } uint8_t resetWire(void){ /*During the initialization sequence the bus master transmits (TX) the reset pulse by pulling the 1-Wire bus low for a minimum of 480µs. The bus master then releases the bus and goes into receive mode (RX). When the bus is released, the 5k? pullup resistor pulls the 1-Wire bus high. When the DS18B20 detects this rising edge, it waits 15µs to 60µs and then transmits a presence pulse by pulling the 1-Wire bus low for 60µs to 240µs.*/ goOutput(); delay_us(480); goInput(); delay_us(140); if(!read_pin()) //The ds18b20 pulls the bus low { delay_us(350); return; } else //If not, wait and try again { delay_us(500); resetWire(); } } void OnewireSendConvertTempCommand(void){ //Send command to convert the temperature resetWire(); SendCMD(SKIP_ROM); SendCMD(CONVER_TEMP); } float OnewireReceivedTemp (void) { uint16_t rawTemp; //wait until receive 1 (conversion done!) while(!ReadBit()); //Read the temperature resetWire() SendCMD(SKIP_ROM); SendCMD(READ_SCRATCH); rawTemp = ReadByte(); rawTemp |= (ReadByte() << 8); return complement2_12bitsResolution(rawTemp); } float OnewireReadTemp(void){ /* After the Convert T command and the DS18B20 will respond by transmitting 0 while the temperature conversion is in progress and 1 when the conversion is done. If the DS18B20 is powered with parasite power, this notification technique cannot be used since the bus must be pulled high by a strong pullup during the entire temperature conversion. Necessary to wait until the 750 ms ( max temperature conversion time for 12-bits resolution) We are powering by external supply */ OnewireSendConvertTempCommand(); return OnewireReceivedTemp(); } float complement2_12bitsResolution (uint16_t rawData) { float temp; //correct the sign (complemento a 2 - 12 bits the resolución) if ((rawData & 0x8000)>0) //negative { temp = ((rawData ^ 0xffff) + 1) * -1; } else //positive { temp=(float)rawData; } return (temp / 16.0); } void goInput (void) { port_get_config_defaults(&pin_conf); pin_conf.input_pull = PULL_SETTING; pin_conf.direction = INPUT; port_pin_set_config(PIN_ONEWIRE, &pin_conf); //PORT->Group[0].DIRCLR.bit.DIRCLR = (1 << PIN_ONEWIRE); //Another way? } void goOutput(void){ port_get_config_defaults(&pin_conf); pin_conf.input_pull = PULL_SETTING; pin_conf.direction = OUTPUT; port_pin_set_config(PIN_ONEWIRE, &pin_conf); //PORT->Group[0].DIRSET.bit.DIRSET = (1 << PIN_ONEWIRE); ////Another way? } /*Note for writing and reading data: All write/read time slots must be a minimum of 60µs in duration with a minimum of a 1µs recovery time between individual write slots.*/ void SendCMD (uint8_t command) { for (int i = 0; i < 8; i++) { goOutput(); if (command & 0x01) { delay_us(10); goInput(); delay_us(60); } else { delay_us(60); goInput(); delay_us(10); } command >>= 1; } } int ReadBit (void){ int inputState; goOutput(); delay_us(6); goInput(); delay_us(9); //inputState= ((PORT->Group[0].IN.bit.IN>>PIN_ONEWIRE) & 0x01); // This could work as well? inputState = port_pin_get_input_level(PIN_ONEWIRE); //Another way?: //Get the value set in the 13th bit and shift it to get 1 or 0 //input = (PORT->Group[0].IN.bit.IN>>PIN_ONEWIRE) & 1UL; delay_us(55); return inputState; } int ReadByte (void){ int byte = 0; int bit = 1; do { if (ReadBit()) { byte |= bit; } bit <<= 1; } while (0x100 != bit); return byte; } //not checked void ReadSerialNumber(void){ uint8_t serialNumber[8]; uint8_t id[6]; int rv = -1; resetWire(); SendCMD(READ_ROM); do { resetWire(); SendCMD(READ_ROM); for (uint16_t i = 0; i < sizeof(serialNumber); ++i) { serialNumber[i] = ReadByte(); } rv = 0; } while (0); if (rv==0) { if (0 != iBSPACMonewireComputeCRC(serialNumber, sizeof(serialNumber))) { rv = -1; } else { for (uint16_t i = 0; i < sizeof(id); ++i) { id[i] = serialNumber[sizeof(serialNumber) - 2 - i]; } } } delay_ms(100); } //not checked int iBSPACMonewireComputeCRC (const unsigned char * romp,int len){ static const unsigned char OW_CRC_POLY = 0x8c; unsigned char crc = 0; while (0 < len--) { int bi; crc ^= *romp++; for (bi = 0; bi < 8; ++bi) { if (crc & 1) { crc = (crc >> 1) ^ OW_CRC_POLY; } else { crc >>= 1; } } } return (int)crc; }
And just in case, my main.c (Not included the functions for initializing the console or so, just the oneWire use):
#include "asf.h" #include "stdio_serial.h" #include "conf_uart_serial.h" #include "oneWire.h" int main(void) { system_init(); /*Configure UART console.*/ configure_console(); /*Initialize the delay driver*/ delay_init(); /* Output example information */ puts(STRING_HEADER); initOneWire(); /*main loop*/ while(1){ OnewireSendConvertTempCommand(); //ReadSerialNumber(); temperature = OnewireReadTemp(); } }
Any more useful information that I code have missed please let me know and I will attach it as soon as possible.
Than you in advance for your time.