Skip to content

Instantly share code, notes, and snippets.

@mattrude
Last active August 26, 2021 01:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattrude/05e26efc310f657d7a4e65c267c1e7ce to your computer and use it in GitHub Desktop.
Save mattrude/05e26efc310f657d7a4e65c267c1e7ce to your computer and use it in GitHub Desktop.
This is a Advanced Traffic Stop Light program written for an ATtiny85 & 74HC595, using Atmel Studio 7.
/* ATtiny85 - Advanced Traffic Stop Light - Version 0.1.1 - 2020-03-20
* Copyright (c) 2020 Matt Rude <matt@mattrude.com>
*
* *********************************************************************************
*
* This is the Advanced Traffic Stop Light program written for an ATtiny85 using
* Atmel Studio 7: https://www.microchip.com/mplab/avr-support/atmel-studio-7
*
* For more on the ATtiny85, see: https://www.microchip.com/wwwproducts/en/ATtiny85
*
* The ATtiny85 was programed with the Tiny AVR programmer PGM-11801 by SparkFun
* Electronics: https://www.sparkfun.com/products/11801
*
* The circuit is powered by an external DC buck converter running at +5v.
*
* *********************************************************************************
*
* Required Hardware:
*
* - 1x ATtiny85 Micro Controller
* - 1x 74HC959 Shift Register
* - 2x Red LED
* - 2x Yellow LED
* - 2x Green LED
* - 6x 220 ohm Resistors
* - 1x Large Breadboard
* - 20x Jumper Wires of various colors
*
* Required Tools:
*
* - Generic Windows 7+ Computer with a free USB port
* - Atmel Studio 7 software
* - Tiny AVR programmer - PGM-11801
* - DC Power Supply
*
* *********************************************************************************
*
* ATtiny85 pin-out:
* (Note: the dot next to the PB5 pin represents the dot on the chip.)
* ______
* (not used) - PB5 - |° | - VCC - 5v+
* (not used) - PB3 - | | - PB2 - To DS on 74HC595
* (not used) - PB4 - | | - PB1 - To STCP on 74HC595
* GND - GND - |______| - PB0 - To SHCP on 74HC595
*
* 74HC959 Shift Register pin-out:
* (Note: the dot next to the Q1 pin represents the dot on the chip.)
* ______
* Red Light - Q1 - |° | - VCC - +5v
* Yellow Light - Q2 - | | - Q0 - Red Walk Sign
* Green Light - Q3 - | | - DS - To PB2 on ATtiny85
* Red turn Arrow - Q4 - | | - OE - GND
* Yellow turn Arrow - Q5 - | | - STCP - To PB1 on ATtiny85
* Green turn Arrow - Q6 - | | - SHCP - To PB0 on ATtiny85
* Green Walk Sign - Q7 - | | - MR - +5v
* GND - GND - |______| - Q7S
*
* *********************************************************************************
*
* Changelog:
*
* 2020-03-20 - 0.1.1 - Correct WDT function to load at start correctly.
* - Minor comment updates
* 2020-03-07 - 0.1.0 - Initial Release
*
* *********************************************************************************
*
* MIT License:
*
* Copyright (c) 2020 Matt Rude <matt@mattrude.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* *********************************************************************************
*/
// Set the default amount of time, in seconds, to wait between light changes.
#define changeDelay 30 // Amount of time to delay light changes in seconds
// Declare the shift register pins
#define clockPin PB0 // Connected to SHCP (pin 11) on the 74HC595.
#define latchPin PB1 // Connected to STCP (pin 12) on the 74HC595.
#define dataPin PB2 // Connected to DS (pin 14) on the 74HC595.
// Set required variables
#define F_CPU 1000000UL // Set the CPU clock frequency to 1MHz
// Include the required libraries for the program
#include <avr/io.h> // Include the IO library
#include <util/delay.h> // Include the Delay library
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/wdt.h> // Include the WatchDog library
// Declare the micros
#define WDTO_1S 6 // Set the watch dog timer to about one second
#define MCUCSR MCUSR // Source of why the last reset happened
#define setHigh(pn) PORTB |= (1<<pn) // Write digital HIGH to pin <pn> on PORTB
#define setLow(pn) PORTB &= ~(1<<pn) // Write digital LOW to pin <pn> on PORTB
// Declare the different light configurations
#define redLight 0b100 // Red (Stop) Light
#define yellowLight 0b010 // Yellow (Slow Down) Light
#define greenLight 0b001 // Green (Go) Light
#define dWalkLight 0b10 // Red Don't Walk Sign
#define walkLight 0b01 // Walk Sign
// Declare the functions
void safeMode(uint8_t); // Run safe mode error function
void feedDog(); // Reset the watchdog timer
void runDelay(uint16_t); // Delay function
void send(uint8_t,uint8_t,uint8_t); // Send a Byte to the Shift Register
void sendBit(uint8_t); // Send a Bit to the Shift Register
void latch(); // Latch the Shift Register
void cycleClock(); // Cycle the Shift Register clock
#define adc_disable() (ADCSRA &= ~(1<<ADEN)) // Disable ADC
// Now that everything is setup, starting the main process
int main(void) {
// Set the three shift register pins as outputs
DDRB |= (1 << clockPin) | (1 << latchPin) | (1 << dataPin);
// Before we start, set the clockPin to LOW
PORTB &= ~(1 << clockPin);
// Check to see if the last ran was finished correctly
if(MCUCSR & (1<<EXTRF)) {
safeMode(2); // External reset!
} else if(MCUCSR & (1<<BORF )) {
safeMode(10); // Brownout reset!
} else if(MCUCSR & (1<<WDRF )) {
safeMode(60); // Watchdog reset!
}
// The start the primary loop
while (1) {
// Set BOTH directions to Red
send(redLight, redLight, dWalkLight);
send(redLight, redLight, dWalkLight);
latch();
runDelay((changeDelay * 1000) / 6);
// Set the first directions to Green and the second to Red
send(greenLight, greenLight, walkLight);
send(redLight, redLight, dWalkLight);
latch();
runDelay(changeDelay);
// Set the first directions to Yellow and keep the second directions Red
send(yellowLight, yellowLight, dWalkLight);
send(redLight, redLight, dWalkLight);
latch();
runDelay((changeDelay * 1000) / 4);
// Set Both directions to Red
send(redLight, redLight, dWalkLight);
send(greenLight, greenLight, walkLight);
latch();
runDelay(changeDelay);
// Set the first directions to Red and the second to Green
send(redLight, greenLight, walkLight);
latch();
runDelay(changeDelay * 1000);
// Set the first directions to Yellow and the second to Red
send(redLight, yellowLight, dWalkLight);
latch();
runDelay((changeDelay * 1000) / 4);
} // Closing the primary loop
} // Closing the main process
// The error function
void safeMode(uint8_t errorReason) {
send(redLight, redLight, dWalkLight);
send(redLight, redLight, dWalkLight);
latch();
_delay_ms(500);
errorReason = ((errorReason)*10);
uint8_t i;
for (i = 0; i < errorReason; i++) {
send(redLight, redLight, dWalkLight);
send(000, 000, 00);
latch();
_delay_ms(500);
send(000, 000, 00);
send(redLight, redLight, dWalkLight);
latch();
_delay_ms(500);
}
} // Closing the safeMode function
// Delay and feed the dog all at the same time
void runDelay(uint16_t delayTime) {
while (delayTime >= 0) {
feedDog();
_delay_ms(500);
feedDog();
_delay_ms(500);
delayTime = (delayTime-1);
}
feedDog();
} // Closing the delay function
// Reset the watch dog timer
void feedDog() {
#define wdt_reset( ) __asm__ __volatile__ ("wdr")
} // Closing the feedDog function
// Writes data to the dataPin
void send(uint8_t toSendMain,uint8_t toSendTurn, uint8_t toSendWalk) {
for (uint8_t a = 0; a < 3; a++) {
sendBit(toSendMain & 1);
toSendMain >>= 1;
}
for (uint8_t b = 0; b < 3; b++) {
sendBit(toSendTurn & 1);
toSendTurn >>= 1;
}
for (uint8_t c = 0; c < 2; c++) {
sendBit(toSendWalk & 1);
toSendWalk >>= 1;
}
} // Closing the send function
// Writes a single bit to the dataPin, then cycles the clock
void sendBit(uint8_t bit) {
if (bit == 0) {
setLow(dataPin);
} else {
setHigh(dataPin);
}
// Once the bit has been written, cycle the clock
cycleClock();
} // Closing the sendBit function
// Tells the shift register to output all the bits it has
void latch() {
setHigh(latchPin);
setLow(latchPin);
} // Closing the latch function
// Tells the shift register to read a bit by ticking the clock forward
void cycleClock() {
setHigh(clockPin);
setLow(clockPin);
} // Closing the cycleClock function
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment