This program is used on a PICAXE 08M2 to read the temperature from a DS18B20 temperature sensor and display it on a 3 digit 7 segment LED display. A MAX7219 LED driver is used to drive the display.
The main processor can also control this chip through 2 inputs; one to control the brightness level, and the other display the temperature in farenheit.
#picaxe 08m2
#no_data
; Project: Word Clock v2.
; File: ReadDisplayTemp.bas
; Description:
; Read temperature from a DS18B20 and display on a three
; digit 7 segment LED display using a MAX7219 LED display
; driver.
;
; Copyright (C) 2014 Marc Symonds
; All rights reserved.
;
; This software may be used and redistributed, with or without
; modification, as long as it is understood that this software
; is provided as-is without any explicit or implied warranties
; of merchantablity or fitness of purpose.
; MAX7219 Pins
symbol MAX7219_LOAD = C.1
symbol MAX7219_CLK = C.0
symbol MAX7219_DIN = C.2
; MAX7219 Registers
symbol MAX7219_NOOP = $00
symbol MAX7219_DIGIT0 = $01
symbol MAX7219_DIGIT1 = $02
symbol MAX7219_DIGIT2 = $03
symbol MAX7219_DIGIT3 = $04
symbol MAX7219_DIGIT4 = $05
symbol MAX7219_DIGIT5 = $06
symbol MAX7219_DIGIT6 = $07
symbol MAX7219_DIGIT7 = $08
symbol MAX7219_DECODE_MODE = $09
symbol MAX7219_INTENSITY = $0A
symbol MAX7219_SCAN_LIMIT = $0B
symbol MAX7219_SHUTDOWN = $0C
symbol MAX7219_TEST_MODE = $0F
; DS18B20 Pins
symbol DS18B20_DQ = C.4
; Pins used by main processor to control display.
symbol DISPLAY_F = C.5 ; Display in Farenheit.
symbol DISPLAY_FP = pinC.5
symbol LOW_BRIGHTNESS = C.3 ; Display brightness high or low.
symbol LOW_BRIGHTNESSP = pinC.3
symbol P_Register = b0
symbol P_Data = b1
symbol V_Temp1 = b3
symbol V_Temp2 = b4
symbol V_Neg = b8
symbol V_TempFrac = b9
symbol V_TempWhole = b10
symbol V_Digit0 = b11
symbol V_Digit1 = b12
symbol V_Digit2 = b13
symbol V_Temperature = w3 ; b6 b7
symbol V_LowBrightness = b14
letThereBeLight:
setfreq m4
; This long delay is to allow the chip to be more easily programmed later,
; because further down we "disconnect" the chip so that it stops looking for
; new downloads.
pause 3000
let V_LowBrightness = 0
input DISPLAY_F
input LOW_BRIGHTNESS
gosub MAX7219_Initialise
; We are using C.5 (serial in) as an input (to display farenheit), so we need
; to stop the chip from scanning the serial in pin looking for a new download.
; Once the disconnect command has run, you have to do a hard-reset to download
; a new program; see the manual.
disconnect
main:
setfreq m4
readtemp12 DS18B20_DQ, V_Temperature
setfreq m8
gosub displayTemp
if LOW_BRIGHTNESSP <> V_LowBrightness then
let V_LowBrightness = LOW_BRIGHTNESSP
if V_LowBrightness = 0 then
let P_Data = $05
else
let P_Data = $0E
end if
gosub MAX7219_SetIntensity
end if
;pause 1000
sleep 2
goto main
; The 3 digit 7 segment display I'm using has some segments that don't work;
; notably the e segment of the first character, and the DP segments of the
; first and third characters.
; So the displaying of the temperature below is a bit more complicated than
; would normally be required, to work around the problems with the display.
displayTemp:
let V_Neg = 0
if V_Temperature > $7FFF then
let V_Temperature = -V_Temperature
let V_Neg = 1
end if
if DISPLAY_FP = 1 then
; Convert C to F. 115/64 = 1.7968 (1.8 ish), and 512 is 32 * 16 (temp from DS18B20 is in 16th's of a degree).
let V_Temperature = V_Temperature * 115 / 64 + 512
end if
let b9 = V_Temperature & 15 * 10 / 16 ; frac
let b10= V_Temperature / 16 ; whole
; Work out what to display in each of the three digits.
if V_Neg = 1 then
let V_Digit0 = 10 ; minus sign.
if b10 > 99 then ; Can't display anything below -99, so show EE. If it's below -99 we're probably dead anyway.
let b12 = 11 ; E
let b13 = 11 ; E
elseif b10 > 9 then
let b12 = b10 / 10
let b13 = b10 % 10
else
let b12 = b10 | $80 ; Turn on DP
let b13 = b9
end if
else
if b10 > 99 then
let b11 = b10 / 100
let b12 = b10 / 10 % 10
let b13 = b10 % 10
elseif b10 < 20 then
if b10 > 9 then
let b11 = b10 / 10
else
let b11 = 15 ; blank
end if
let b12 = b10 % 10 | $80 ; Turn on DP
let b13 = b9
else
let b11 = 15
let b12 = b10 / 10
let b13 = b10 % 10
end if
end if
; Display it.
let b0 = MAX7219_DIGIT0
let b1 = b11
gosub MAX7219_SendCmdAndDataTo1
let b0 = MAX7219_DIGIT1
let b1 = b12
gosub MAX7219_SendCmdAndDataTo1
let b0 = MAX7219_DIGIT2
let b1 = b13
gosub MAX7219_SendCmdAndDataTo1
return
; ********************************************************************************
; *** MAX7219 Functions **********************************************************
; ********************************************************************************
MAX7219_Initialise:
output MAX7219_LOAD
output MAX7219_CLK
output MAX7219_DIN
low MAX7219_LOAD
low MAX7219_CLK
low MAX7219_DIN
pause 10
gosub MAX7219_TestModeOff
gosub MAX7219_ShutdownOff
let b0 = MAX7219_SCAN_LIMIT
let b1 = $02 ; Using 3 digits.
gosub MAX7219_SendCmdAndDataTo1
let b0 = MAX7219_DECODE_MODE
let b1 = $7 ; Use BCD for digits 0, 1 and 2.
gosub MAX7219_SendCmdAndDataTo1
let b1 = $0C ' Max brightness.
gosub MAX7219_SetIntensity
return
MAX7219_ShutdownOff:
let b0 = MAX7219_SHUTDOWN
let b1 = $01
goto MAX7219_SendCmdAndDataTo1 ; Return will be peformed by this function
#rem
MAX7219_ShutdownOn:
let b0 = MAX7219_SHUTDOWN
let b1 = $00
goto MAX7219_SendCmdAndDataToBoth ; Return will be peformed by this function
#endrem
MAX7219_TestModeOn:
let b1 = $01
goto MAX7219_TestModeSet ; Return will be peformed by this function
MAX7219_TestModeOff:
let b1 = $00
MAX7219_TestModeSet:
let b0 = MAX7219_TEST_MODE
goto MAX7219_SendCmdAndDataTo1 ; Return will be peformed by this function
MAX7219_SetIntensity:
; b1 = Intensity level for top half.
; b2 = Intensirt level for bottom half.
let b0 = MAX7219_INTENSITY
; *** Fall-through ***
MAX7219_SendCmdAndDataTo1:
; b0 = Register.
; b1 = Data for chip 1.
gosub MAX7219_SendCmdAndData
; For 7219 you only need to pulse the LOAD pin to load the data.
pulsout MAX7219_LOAD, 1
return
MAX7219_SendCmdAndData:
; b0 = Register.
; b1 = Data.
; b3 & b4 used as temp.
let b3 = b0
gosub MAX7219_Send
let b3 = b1
; *** Fall-through is intended. ***
MAX7219_Send:
; b3 = Data to send
for b4 = 0 to 7
if b3 > 127 then
high MAX7219_DIN
else
low MAX7219_DIN
end if
pulsout MAX7219_CLK, 1
b3 = b3 * 2
next
low MAX7219_DIN
return
#rem
3 Digit/7 Segment display Pins
1 1 1 a
2 1 0 9 8 7 ---
| | | | | | f| |b
+-----------+ | g |
| | ---
| 8. 8. 8. | e| |c
| | | |
+-----------+ --- O
| | | | | | d
1 2 3 4 5 6
1 = Digit 0 cathode
2 = Segment e
3 = Segment d
4 = Digit 1 cathode
5 = Segment c
6 = DP
7 = Digit 2 cathode
8 = Segment b
9 = Segment g
10 = Segment a
11 = Segment f
12 = NC
#endrem
4017 Decade Counter
Counter_4017.h
/* Project: 4017 Decade Counter Interfacing.
* File: Counter_4017.h
* Description: Interface with a 4017 decade counter.
* Uses the DirectIO library.
*
* Copyright (C) 2014 Marc Symonds
* All rights reserved.
*
* This software may be used and redistributed, with or without
* modification, as long as it is understood that this software
* is provided as-is without any explicit or implied warranties
* of merchantablity or fitness of purpose.
*/
#ifndef Counter_4017_h
#define Counter_4017_h
#include "Arduino.h"
#include "DirectIO.h"
class Counter_4017
{
public:
Counter_4017(byte clockPin, byte lastElementDetectPin);
void clock();
void clockPrime();
void clockTrigger();
void clear();
boolean onLastElement();
private:
DIO_SetPinFPtr _clockPin;
byte _lastElementDetectPin;
};
#endif
Counter_4017.cpp
/* Project: 4017 Decade Counter Interfacing.
* File: Counter_4017.cpp
* Description: Interface with a 4017 decade counter.
* Uses the DirectIO library.
*
* Copyright (C) 2014 Marc Symonds
* All rights reserved.
*
* This software may be used and redistributed, with or without
* modification, as long as it is understood that this software
* is provided as-is without any explicit or implied warranties
* of merchantability or fitness of purpose.
*/
#include "Arduino.h"
#include "Counter_4017.h"
Counter_4017::Counter_4017(byte clockPin, byte lastElementDetectPin)
{
pinMode(clockPin, OUTPUT);
pinMode(lastElementDetectPin, INPUT);
_clockPin = DIO_GetSetPinFunction(clockPin);
_lastElementDetectPin = lastElementDetectPin;
clear();
}
void Counter_4017::clock()
{
_clockPin(false);
_clockPin(true);
}
void Counter_4017::clockTrigger()
{
_clockPin(true);
}
void Counter_4017::clockPrime()
{
_clockPin(false);
}
void Counter_4017::clear()
{
while (!onLastElement())
clock();
while (onLastElement())
clock();
}
boolean Counter_4017::onLastElement()
{
return (digitalRead(_lastElementDetectPin) == HIGH ? true : false);
}
keywords.txt
Counter_4017 KEYWORD1
clock KEYWORD2
clear KEYWORD2
onLastElement KEYWORD2
Directly setting IO pins high or low
See 7495 Shift Register for an example of how these can be used.
DirectIO.h
/* Project: Direct digital pin access for Arduino UNO.
* File: DirectIO.h
* Description: Manipulate digital IO pins directly. Depending
* method used can be much faster than digitalWrite().
*
* Copyright (C) 2014 Marc Symonds
* All rights reserved.
*
* This software may be used and redistributed, with or without
* modification, as long as it is understood that this software
* is provided as-is without any explicit or implied warranties
* of merchantability or fitness of purpose.
*/
#ifndef DirectIO_h
#define DirectIO_h
#include "Arduino.h"
/* These are about 4 times faster than digitalWrite(); */
void DIO_SetPin4(boolean);
void DIO_SetPin7(boolean);
void DIO_SetPin8(boolean);
void DIO_SetPin9(boolean);
void DIO_SetPin10(boolean);
void DIO_SetPin11(boolean);
void DIO_SetPin12(boolean);
void DIO_SetPin13(boolean);
void DIO_SetPinNull(boolean);
void DIO_SetPin(int pin, boolean state);
typedef void (*DIO_SetPinFPtr)(boolean);
DIO_SetPinFPtr DIO_GetSetPinFunction(byte);
/* These are about 30 times faster than using digitalWrite(); */
static inline void PIN4H() { PORTD = PORTD | B00010000; }
static inline void PIN4L() { PORTD = PORTD & B11101111; }
static inline void PIN7H() { PORTD = PORTD | B10000000; }
static inline void PIN7L() { PORTD = PORTD & B01111111; }
static inline void PIN8H() { PORTB = PORTB | B00000001; }
static inline void PIN8L() { PORTB = PORTB & B11111110; }
static inline void PIN9H() { PORTB = PORTB | B00000010; }
static inline void PIN9L() { PORTB = PORTB & B11111101; }
static inline void PIN10H() { PORTB = PORTB | B00000100; }
static inline void PIN10L() { PORTB = PORTB & B11111011; }
static inline void PIN11H() { PORTB = PORTB | B00001000; }
static inline void PIN11L() { PORTB = PORTB & B11110111; }
static inline void PIN12H() { PORTB = PORTB | B00010000; }
static inline void PIN12L() { PORTB = PORTB & B11101111; }
static inline void PIN13H() { PORTB = PORTB | B00100000; }
static inline void PIN13L() { PORTB = PORTB & B11011111; }
/* The inline functions above are as fast as the code below. */
#define PIN13Hi PORTB = PORTB | B00100000
#define PIN13Li PORTB = PORTB & B11011111
#define PIN13Ha asm("SBI 5, 5\n")
#define PIN13La asm("CBI 5, 5\n")
#endif
DirectIO.cpp
/* Project: Direct digital pin access for Arduino UNO.
* File: DirectIO.cpp
* Description: Manipulate digital IO pins directly. Depending
* method used can be much faster than digitalWrite().
*
* Copyright (C) 2014 Marc Symonds
* All rights reserved.
*
* This software may be used and redistributed, with or without
* modification, as long as it is understood that this software
* is provided as-is without any explicit or implied warranties
* of merchantability or fitness of purpose.
*/
#include "Arduino.h"
#include "DirectIO.h"
/*
Direct digital port manipulation using the PORT variables.
About 4 times quicker than using digitalWrite().
*/
/*
Returns a pointer to the function that can turn set the specified port high or low.
DIO_SetPinFPtr func;
func = DIO_getSetPinFunction(4);
func(true); // Set high.
func(low); // Set low.
You could, of course, just as easily call the DIO_set4 fuction directly.
*/
DIO_SetPinFPtr DIO_GetSetPinFunction(byte pin)
{
switch(pin)
{
case 4:
return DIO_SetPin4;
break;
case 7:
return DIO_SetPin7;
break;
case 8:
return DIO_SetPin8;
break;
case 9:
return DIO_SetPin9;
break;
case 10:
return DIO_SetPin10;
break;
case 11:
return DIO_SetPin11;
break;
case 12:
return DIO_SetPin12;
break;
case 13:
return DIO_SetPin13;
}
return DIO_SetPinNull;
}
void DIO_SetPinNull(boolean state)
{
// Do nothing
}
void DIO_SetPin4(boolean state)
{
if (state)
PIN4H();
else
PIN4L();
}
void DIO_SetPin7(boolean state)
{
if (state)
PIN7H();
else
PIN7L();
}
void DIO_SetPin8(boolean state)
{
if (state)
PIN8H();
else
PIN8L();
}
void DIO_SetPin9(boolean state)
{
if (state)
PIN9H();
else
PIN9L();
}
void DIO_SetPin10(boolean state)
{
if (state)
PIN10H();
else
PIN10L();
}
void DIO_SetPin11(boolean state)
{
if (state)
PIN11H();
else
PIN11L();
}
void DIO_SetPin12(boolean state)
{
if (state)
PIN12H();
else
PIN12L();
}
void DIO_SetPin13(boolean state)
{
if (state)
PIN13H();
else
PIN13L();
}
void DIO_SetPin(int pin, boolean state)
{
if (state)
{
switch(pin)
{
case 4:
PIN4H();
break;
case 7:
PIN7H();
break;
case 8:
PIN8H();
break;
case 9:
PIN9H();
break;
case 10:
PIN10H();
break;
case 11:
PIN11H();
break;
case 12:
PIN12H();
break;
case 13:
PIN13H();
break;
}
}
else
{
switch(pin)
{
case 4:
PIN4L();
break;
case 7:
PIN7L();
break;
case 8:
PIN8L();
break;
case 9:
PIN9L();
break;
case 10:
PIN10L();
break;
case 11:
PIN11L();
break;
case 12:
PIN12L();
break;
case 13:
PIN13L();
break;
}
}
}
keywords.txt
ShiftReg_7495 KEYWORD1
DIO_SetPin4 KEYWORD2
DIO_SetPin7 KEYWORD2
DIO_SetPin8 KEYWORD2
DIO_SetPin9 KEYWORD2
DIO_SetPin10 KEYWORD2
DIO_SetPin11 KEYWORD2
DIO_SetPin12 KEYWORD2
DIO_SetPin13 KEYWORD2
DIO_SetPin KEYWORD2
PIN4L KEYWORD2
PIN4H KEYWORD2
PIN7L KEYWORD2
PIN7H KEYWORD2
PIN8L KEYWORD2
PIN8H KEYWORD2
PIN9L KEYWORD2
PIN9H KEYWORD2
PIN10L KEYWORD2
PIN10H KEYWORD2
PIN11L KEYWORD2
PIN11H KEYWORD2
PIN12L KEYWORD2
PIN12H KEYWORD2
PIN13L KEYWORD2
PIN13H KEYWORD2
SW7495 4-Bit (non-latching) Shift Register
Library for sending data to the 7495 shift register. This is a simple 4-bit non-latching type which can work in parallel or serial mode.
This uses the Direct IO library to speed up the setting of the pins used to control the chip.
ShiftReg_7495.h
/* Project: 7495 4-Bit Shift Register Interfacing.
* File: Shift_7495.h
* Description: Interface with a 7495 4-bit shift register in
* parallel or serial mode.
* Uses the DirectIO library.
*
* Copyright (C) 2014 Marc Symonds
* All rights reserved.
*
* This software may be used and redistributed, with or without
* modification, as long as it is understood that this software
* is provided as-is without any explicit or implied warranties
* of merchantability or fitness of purpose.
*/
#ifndef ShiftReg_7495_h
#define ShiftReg_7495_h
#include "Arduino.h"
#include "DirectIO.h"
class ShiftReg_7495
{
public:
ShiftReg_7495(byte clockPin, byte dataPin); // Serial mode.
ShiftReg_7495(byte clockPin, byte aPin, byte bPin, byte cPin); // Parallel mode.
void setBit(byte bit, boolean state);
void send();
void sendPrime();
void sendTrigger();
void clear();
private:
DIO_SetPinFPtr _clockPin;
DIO_SetPinFPtr _dataPin;
DIO_SetPinFPtr _aPin;
DIO_SetPinFPtr _bPin;
DIO_SetPinFPtr _cPin;
boolean _currBits[3];
boolean _newBits[3];
boolean _serialMode;
void sendBit(boolean state);
};
#endif
ShiftReg_7495.cpp
/* Project: 7495 4-Bit Shift Register Interfacing.
* File: Shift_7495.cpp
* Description: Interface with a 7495 4-bit shift register in
* parallel or serial mode.
* Uses the DirectIO library.
*
* Copyright (C) 2014 Marc Symonds
* All rights reserved.
*
* This software may be used and redistributed, with or without
* modification, as long as it is understood that this software
* is provided as-is without any explicit or implied warranties
* of merchantability or fitness of purpose.
*/
#include "Arduino.h"
#include "ShiftReg_7495.h"
#include "DirectIO.h"
// Constructor for serial mode.
ShiftReg_7495::ShiftReg_7495(byte clockPin, byte dataPin)
{
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
_clockPin = DIO_GetSetPinFunction(clockPin);
_dataPin = DIO_GetSetPinFunction(dataPin);
_clockPin(true);
_serialMode = true;
clear();
}
// Constructor for parallel mode.
ShiftReg_7495::ShiftReg_7495(byte clockPin, byte aPin, byte bPin, byte cPin)
{
pinMode(clockPin, OUTPUT);
pinMode(aPin, OUTPUT);
pinMode(bPin, OUTPUT);
pinMode(cPin, OUTPUT);
_clockPin = DIO_GetSetPinFunction(clockPin);
_aPin = DIO_GetSetPinFunction(aPin);
_bPin = DIO_GetSetPinFunction(bPin);
_cPin = DIO_GetSetPinFunction(cPin);
_clockPin(true);
_serialMode = false;
clear();
}
void ShiftReg_7495::setBit(byte bit, boolean state)
{
_newBits[bit] = state;
}
// Send the data to the 7495 - Serial or parallel.
void ShiftReg_7495::send()
{
if (_serialMode)
{
if (_currBits[0] == _newBits[0] && _currBits[1] == _newBits[1] && _currBits[2] == _newBits[2])
; // Don't need to do anything, the register aleady contains the bits we are going to show.
else
{
if (_newBits[2] == _currBits[1] && _newBits[1] == _currBits[0])
sendBit(_newBits[0]);
else
{
if (_newBits[2] != _currBits[0])
sendBit(_newBits[2]);
sendBit(_newBits[1]);
sendBit(_newBits[0]);
}
_currBits[0] = _newBits[0];
_currBits[1] = _newBits[1];
_currBits[2] = _newBits[2];
}
}
else
{
sendPrime();
sendTrigger();
}
}
void ShiftReg_7495::sendPrime()
{
_clockPin(true);
_aPin(_newBits[0]);
_bPin(_newBits[1]);
_cPin(_newBits[2]);
}
void ShiftReg_7495::sendTrigger()
{
_clockPin(false);
}
void ShiftReg_7495::sendBit(boolean state)
{
_clockPin(true);
_dataPin(state);
_clockPin(false);
}
void ShiftReg_7495::clear()
{
for (byte i = 0 ; i < 3 ; i++)
{
_currBits[i] = true;
_newBits[i] = false;
}
send();
}
keywords.txt
ShiftReg_7495 KEYWORD1
setBit KEYWORD2
send KEYWORD2
sendPrime KEYWORD2
sendTrigger KEYWORD2
clear KEYWORD2
Some Arduino code that I have written for various projects:-
Recent Comments