Created
September 27, 2018 14:14
-
-
Save cheewee2000/c896f4ab995cc2f10511c36145ab15a7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This simplified demo scrolls the text of the Jaberwoky poem directly from flash memory | |
// Full article at http://wp.josh.com/2016/05/20/huge-scrolling-arduino-led-sign/ | |
// Change this to be at least as long as your pixel string (too long will work fine, just be a little slower) | |
#define PIXELS 96*4 // Number of pixels in the string. I am using 4 meters of 96LED/M | |
// These values depend on which pins your 8 strings are connected to and what board you are using | |
// More info on how to find these at http://www.arduino.cc/en/Reference/PortManipulation | |
// PORTD controls Digital Pins 0-7 on the Uno | |
// You'll need to look up the port/bit combination for other boards. | |
// Note that you could also include the DigitalWriteFast header file to not need to to this lookup. | |
#define PIXEL_PORT PORTB // Port of the pin the pixels are connected to | |
#define PIXEL_DDR DDRB // Port of the pin the pixels are connected to | |
//connecting to PORTB on an arduino YUN | |
//11 10 9 8 MISO MOSI SCK | |
//static const uint8_t onBits = 0b11011111; // Bit pattern to write to port to turn on all pins connected to LED strips. | |
static const uint8_t onBits = 0b11111110; // Bit pattern to write to port to turn on all pins connected to LED strips. | |
// If you do not want to use all 8 pins, you can mask off the ones you don't want | |
// Note that these will still get 0 written to them when we send pixels | |
// TODO: If we have time, we could even add a variable that will and/or into the bits before writing to the port to support any combination of bits/values | |
// These are the timing constraints taken mostly from | |
// imperically measuring the output from the Adafruit library strandtest program | |
// Note that some of these defined values are for refernce only - the actual timing is determinted by the hard code. | |
#define T1H 814 // Width of a 1 bit in ns - 13 cycles | |
#define T1L 438 // Width of a 1 bit in ns - 7 cycles | |
#define T0H 312 // Width of a 0 bit in ns - 5 cycles | |
#define T0L 936 // Width of a 0 bit in ns - 15 cycles | |
// Phase #1 - Always 1 - 5 cycles | |
// Phase #2 - Data part - 8 cycles | |
// Phase #3 - Always 0 - 7 cycles | |
#define RES 500000 // Width of the low gap between bits to cause a frame to latch | |
// Here are some convience defines for using nanoseconds specs to generate actual CPU delays | |
#define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives | |
#define CYCLES_PER_SEC (F_CPU) | |
#define NS_PER_CYCLE ( NS_PER_SEC / CYCLES_PER_SEC ) | |
#define NS_TO_CYCLES(n) ( (n) / NS_PER_CYCLE ) | |
// Sends a full 8 bits down all the pins, represening a single color of 1 pixel | |
// We walk though the 8 bits in colorbyte one at a time. If the bit is 1 then we send the 8 bits of row out. Otherwise we send 0. | |
// We send onBits at the first phase of the signal generation. We could just send 0xff, but that mught enable pull-ups on pins that we are not using. | |
/// Unforntunately we have to drop to ASM for this so we can interleave the computaions durring the delays, otherwise things get too slow. | |
// OnBits is the mask of which bits are connected to strips. We pass it on so that we | |
// do not turn on unused pins becuase this would enable the pullup. Also, hopefully passing this | |
// will cause the compiler to allocate a Register for it and avoid a reload every pass. | |
static inline void sendBitx8( const uint8_t row , const uint8_t colorbyte , const uint8_t onBits ) { | |
asm volatile ( | |
"L_%=: \n\r" | |
"out %[port], %[onBits] \n\t" // (1 cycles) - send either T0H or the first part of T1H. Onbits is a mask of which bits have strings attached. | |
// Next determine if we are going to be sending 1s or 0s based on the current bit in the color.... | |
"mov r0, %[bitwalker] \n\t" // (1 cycles) | |
"and r0, %[colorbyte] \n\t" // (1 cycles) - is the current bit in the color byte set? | |
"breq OFF_%= \n\t" // (1 cycles) - bit in color is 0, then send full zero row (takes 2 cycles if branch taken, count the extra 1 on the target line) | |
// If we get here, then we want to send a 1 for every row that has an ON dot... | |
"nop \n\t " // (1 cycles) | |
"out %[port], %[row] \n\t" // (1 cycles) - set the output bits to [row] This is phase for T0H-T1H. | |
// ========== | |
// (5 cycles) - T0H (Phase #1) | |
"nop \n\t nop \n\t " // (2 cycles) | |
"nop \n\t nop \n\t " // (2 cycles) | |
"nop \n\t nop \n\t " // (2 cycles) | |
"nop \n\t " // (1 cycles) | |
"out %[port], __zero_reg__ \n\t" // (1 cycles) - set the output bits to 0x00 based on the bit in colorbyte. This is phase for T0H-T1H | |
// ========== | |
// (8 cycles) - Phase #2 | |
"ror %[bitwalker] \n\t" // (1 cycles) - get ready for next pass. On last pass, the bit will end up in C flag | |
"brcs DONE_%= \n\t" // (1 cycles) Exit if carry bit is set as a result of us walking all 8 bits. We assume that the process around us will tak long enough to cover the phase 3 delay | |
"nop \n\t \n\t " // (1 cycles) - When added to the 5 cycles in S:, we gte the 7 cycles of T1L | |
"jmp L_%= \n\t" // (3 cycles) | |
// (1 cycles) - The OUT on the next pass of the loop | |
// ========== | |
// (7 cycles) - T1L | |
"OFF_%=: \n\r" // (1 cycles) Note that we land here becuase of breq, which takes takes 2 cycles | |
"out %[port], __zero_reg__ \n\t" // (1 cycles) - set the output bits to 0x00 based on the bit in colorbyte. This is phase for T0H-T1H | |
// ========== | |
// (5 cycles) - T0H | |
"ror %[bitwalker] \n\t" // (1 cycles) - get ready for next pass. On last pass, the bit will end up in C flag | |
"brcs DONE_%= \n\t" // (1 cycles) Exit if carry bit is set as a result of us walking all 8 bits. We assume that the process around us will tak long enough to cover the phase 3 delay | |
"nop \n\t nop \n\t " // (2 cycles) | |
"nop \n\t nop \n\t " // (2 cycles) | |
"nop \n\t nop \n\t " // (2 cycles) | |
"nop \n\t nop \n\t " // (2 cycles) | |
"nop \n\t " // (1 cycles) | |
"jmp L_%= \n\t" // (3 cycles) | |
// (1 cycles) - The OUT on the next pass of the loop | |
// ========== | |
//(15 cycles) - T0L | |
"DONE_%=: \n\t" | |
// Don't need an explicit delay here since the overhead that follows will always be long enough | |
:: | |
[port] "I" (_SFR_IO_ADDR(PIXEL_PORT)), | |
[row] "d" (row), | |
[onBits] "d" (onBits), | |
[colorbyte] "d" (colorbyte ), // Phase 2 of the signal where the actual data bits show up. | |
[bitwalker] "r" (0x80) // Alocate a register to hold a bit that we will walk down though the color byte | |
); | |
// Note that the inter-bit gap can be as long as you want as long as it doesn't exceed the reset timeout (which is A long time) | |
} | |
// Just wait long enough without sending any bots to cause the pixels to latch and display the last sent frame | |
void show() { | |
delayMicroseconds( (RES / 1000UL) + 1); // Round up since the delay must be _at_least_ this long (too short might not work, too long not a problem) | |
} | |
// Send 3 bytes of color data (R,G,B) for a signle pixel down all the connected stringsat the same time | |
// A 1 bit in "row" means send the color, a 0 bit means send black. | |
static inline void sendRowRGB( uint8_t row , uint8_t r, uint8_t g, uint8_t b ) { | |
//if(row>0 && row < 64) row--; | |
sendBitx8( row , g , onBits); // WS2812 takes colors in GRB order | |
sendBitx8( row , r , onBits); // WS2812 takes colors in GRB order | |
sendBitx8( row , b , onBits); // WS2812 takes colors in GRB order | |
} | |
// This nice 5x7 font from here... | |
// http://sunge.awardspace.com/glcd-sd/node4.html | |
// Font details: | |
// 1) Each char is fixed 5x7 pixels. | |
// 2) Each byte is one column. | |
// 3) Columns are left to right order, leftmost byte is leftmost column of pixels. | |
// 4) Each column is 8 bits high. | |
// 5) Bit #7 is top line of char, Bit #1 is bottom. | |
// 6) Bit #0 is always 0, becuase this pin is used as serial input and setting to 1 would enable the pull-up. | |
// defines ascii characters 0x20-0x7F (32-127) | |
// PROGMEM after variable name as per https://www.arduino.cc/en/Reference/PROGMEM | |
#define FONT_WIDTH 5 | |
#define INTERCHAR_SPACE 1 | |
#define ASCII_OFFSET 0x20 // ASSCI code of 1st char in font array | |
const uint8_t Font5x7[] PROGMEM = { | |
0x00, 0x00, 0x00, 0x00, 0x00, // | |
0x00, 0x00, 0xfa, 0x00, 0x00, // ! | |
0x00, 0xe0, 0x00, 0xe0, 0x00, // " | |
0x28, 0xfe, 0x28, 0xfe, 0x28, // # | |
0x24, 0x54, 0xfe, 0x54, 0x48, // $ | |
0xc4, 0xc8, 0x10, 0x26, 0x46, // % | |
0x6c, 0x92, 0xaa, 0x44, 0x0a, // & | |
0x00, 0xa0, 0xc0, 0x00, 0x00, // ' | |
0x00, 0x38, 0x44, 0x82, 0x00, // ( | |
0x00, 0x82, 0x44, 0x38, 0x00, // ) | |
0x10, 0x54, 0x38, 0x54, 0x10, // * | |
0x10, 0x10, 0x7c, 0x10, 0x10, // + | |
0x00, 0x0a, 0x0c, 0x00, 0x00, // , | |
0x10, 0x10, 0x10, 0x10, 0x10, // - | |
0x00, 0x06, 0x06, 0x00, 0x00, // . | |
0x04, 0x08, 0x10, 0x20, 0x40, // / | |
0x7c, 0x8a, 0x92, 0xa2, 0x7c, // 0 | |
0x00, 0x42, 0xfe, 0x02, 0x00, // 1 | |
0x42, 0x86, 0x8a, 0x92, 0x62, // 2 | |
0x84, 0x82, 0xa2, 0xd2, 0x8c, // 3 | |
0x18, 0x28, 0x48, 0xfe, 0x08, // 4 | |
0xe4, 0xa2, 0xa2, 0xa2, 0x9c, // 5 | |
0x3c, 0x52, 0x92, 0x92, 0x0c, // 6 | |
0x80, 0x8e, 0x90, 0xa0, 0xc0, // 7 | |
0x6c, 0x92, 0x92, 0x92, 0x6c, // 8 | |
0x60, 0x92, 0x92, 0x94, 0x78, // 9 | |
0x00, 0x6c, 0x6c, 0x00, 0x00, // : | |
0x00, 0x6a, 0x6c, 0x00, 0x00, // ; | |
0x00, 0x10, 0x28, 0x44, 0x82, // < | |
0x28, 0x28, 0x28, 0x28, 0x28, // = | |
0x82, 0x44, 0x28, 0x10, 0x00, // > | |
0x40, 0x80, 0x8a, 0x90, 0x60, // ? | |
0x4c, 0x92, 0x9e, 0x82, 0x7c, // @ | |
0x7e, 0x88, 0x88, 0x88, 0x7e, // A | |
0xfe, 0x92, 0x92, 0x92, 0x6c, // B | |
0x7c, 0x82, 0x82, 0x82, 0x44, // C | |
0xfe, 0x82, 0x82, 0x44, 0x38, // D | |
0xfe, 0x92, 0x92, 0x92, 0x82, // E | |
0xfe, 0x90, 0x90, 0x80, 0x80, // F | |
0x7c, 0x82, 0x82, 0x8a, 0x4c, // G | |
0xfe, 0x10, 0x10, 0x10, 0xfe, // H | |
0x00, 0x82, 0xfe, 0x82, 0x00, // I | |
0x04, 0x02, 0x82, 0xfc, 0x80, // J | |
0xfe, 0x10, 0x28, 0x44, 0x82, // K | |
0xfe, 0x02, 0x02, 0x02, 0x02, // L | |
0xfe, 0x40, 0x20, 0x40, 0xfe, // M | |
0xfe, 0x20, 0x10, 0x08, 0xfe, // N | |
0x7c, 0x82, 0x82, 0x82, 0x7c, // O | |
0xfe, 0x90, 0x90, 0x90, 0x60, // P | |
0x7c, 0x82, 0x8a, 0x84, 0x7a, // Q | |
0xfe, 0x90, 0x98, 0x94, 0x62, // R | |
0x62, 0x92, 0x92, 0x92, 0x8c, // S | |
0x80, 0x80, 0xfe, 0x80, 0x80, // T | |
0xfc, 0x02, 0x02, 0x02, 0xfc, // U | |
0xf8, 0x04, 0x02, 0x04, 0xf8, // V | |
0xfe, 0x04, 0x18, 0x04, 0xfe, // W | |
0xc6, 0x28, 0x10, 0x28, 0xc6, // X | |
0xc0, 0x20, 0x1e, 0x20, 0xc0, // Y | |
0x86, 0x8a, 0x92, 0xa2, 0xc2, // Z | |
0x00, 0x00, 0xfe, 0x82, 0x82, // [ | |
0x40, 0x20, 0x10, 0x08, 0x04, // (backslash) | |
0x82, 0x82, 0xfe, 0x00, 0x00, // ] | |
0x20, 0x40, 0x80, 0x40, 0x20, // ^ | |
0x02, 0x02, 0x02, 0x02, 0x02, // _ | |
0x00, 0x80, 0x40, 0x20, 0x00, // ` | |
0x04, 0x2a, 0x2a, 0x2a, 0x1e, // a | |
0xfe, 0x12, 0x22, 0x22, 0x1c, // b | |
0x1c, 0x22, 0x22, 0x22, 0x04, // c | |
0x1c, 0x22, 0x22, 0x12, 0xfe, // d | |
0x1c, 0x2a, 0x2a, 0x2a, 0x18, // e | |
0x10, 0x7e, 0x90, 0x80, 0x40, // f | |
0x10, 0x28, 0x2a, 0x2a, 0x3c, // g | |
0xfe, 0x10, 0x20, 0x20, 0x1e, // h | |
0x00, 0x22, 0xbe, 0x02, 0x00, // i | |
0x04, 0x02, 0x22, 0xbc, 0x00, // j | |
0x00, 0xfe, 0x08, 0x14, 0x22, // k | |
0x00, 0x82, 0xfe, 0x02, 0x00, // l | |
0x3e, 0x20, 0x18, 0x20, 0x1e, // m | |
0x3e, 0x10, 0x20, 0x20, 0x1e, // n | |
0x1c, 0x22, 0x22, 0x22, 0x1c, // o | |
0x3e, 0x28, 0x28, 0x28, 0x10, // p | |
0x10, 0x28, 0x28, 0x18, 0x3e, // q | |
0x3e, 0x10, 0x20, 0x20, 0x10, // r | |
0x12, 0x2a, 0x2a, 0x2a, 0x04, // s | |
0x20, 0xfc, 0x22, 0x02, 0x04, // t | |
0x3c, 0x02, 0x02, 0x04, 0x3e, // u | |
0x38, 0x04, 0x02, 0x04, 0x38, // v | |
0x3c, 0x02, 0x0c, 0x02, 0x3c, // w | |
0x22, 0x14, 0x08, 0x14, 0x22, // x | |
0x30, 0x0a, 0x0a, 0x0a, 0x3c, // y | |
0x22, 0x26, 0x2a, 0x32, 0x22, // z | |
0x00, 0x10, 0x6c, 0x82, 0x00, // { | |
0x00, 0x00, 0xfe, 0x00, 0x00, // | | |
0x00, 0x82, 0x6c, 0x10, 0x00, // } | |
0x10, 0x10, 0x54, 0x38, 0x10, // ~ | |
0x10, 0x38, 0x54, 0x10, 0x10, // | |
}; | |
// Send the pixels to form the specified char, not including interchar space | |
// skip is the number of pixels to skip at the begining to enable sub-char smooth scrolling | |
// TODO: Subtract the offset from the char before starting the send sequence to save time if nessisary | |
// TODO: Also could pad the begining of the font table to aovid the offset subtraction at the cost of 20*8 bytes of progmem | |
// TODO: Could pad all chars out to 8 bytes wide to turn the the multiply by FONT_WIDTH into a shift | |
static inline void sendChar( uint8_t c , uint8_t skip , uint8_t r, uint8_t g, uint8_t b ) { | |
const uint8_t *charbase = Font5x7 + (( c - ' ') * FONT_WIDTH ) ; | |
uint8_t col = FONT_WIDTH; | |
while (skip--) { | |
charbase++; | |
col--; | |
} | |
while (col--) { | |
// sendRowRGB( pgm_read_byte_near( charbase++ ) , r , g , b ); | |
sendRowRGB( pgm_read_byte_near(charbase++) , r , g , b ); | |
} | |
col = INTERCHAR_SPACE; | |
while (col--) { | |
sendRowRGB( 0 , r , g , b ); // Interchar space | |
} | |
} | |
// Show the passed string. The last letter of the string will be in the rightmost pixels of the display. | |
// Skip is how many cols of the 1st char to skip for smooth scrolling | |
static inline void sendString( const char *s , uint8_t skip , const uint8_t r, const uint8_t g, const uint8_t b ) { | |
unsigned int l = PIXELS / (FONT_WIDTH + INTERCHAR_SPACE); | |
sendChar( *s , skip , r , g , b ); // First char is special case becuase it can be stepped for smooth scrolling | |
while ( *(++s) && l--) { | |
sendChar( *s , 0, r , g , b ); | |
} | |
show(); | |
} | |
#include <Process.h> | |
char c [] = " " | |
"loading................" | |
" " | |
"loading................" | |
" " | |
"loading................" | |
" " | |
"loading................" | |
" " | |
"loading................" | |
"loading................" | |
" " | |
"loading................" | |
" " | |
"loading................" | |
"loading................" | |
" " | |
"loading................" | |
" " | |
"loading................" | |
; | |
unsigned long previousMillis = 0; | |
unsigned long interval = 150000L;//5*60*1000L; | |
void setup() { | |
PIXEL_DDR |= onBits; // Set used pins to output mode | |
Bridge.begin(); //disables pin 0, 1 | |
//Serial.begin(9600); | |
//while (!Serial); | |
delay(5000); | |
runCurl(); | |
} | |
void loop() { | |
unsigned long currentMillis = millis(); | |
if (currentMillis - previousMillis > interval) { | |
previousMillis = currentMillis; | |
runCurl(); | |
} | |
//if (millis() > 5 * 60 * 1000 && millis() % int(20 * 60 * 1000) < 500) runCurl(); | |
const char *m = c; | |
while (*m) { | |
for ( uint8_t step = 0; step < FONT_WIDTH + INTERCHAR_SPACE ; step++ ) { // step though each column of the 1st char for smooth scrolling | |
cli(); | |
sendString( m , step , 30, 30, 7 ); | |
sei(); | |
delay(2); | |
} | |
m++; | |
} | |
if (millis() % 2000 < 1000) digitalWrite(14, HIGH); | |
else digitalWrite(14, LOW); | |
} | |
void runCurl() { | |
// curl is command line program for transferring data using different internet protocols | |
Process p; // Create a process and call it "p" | |
p.begin("curl"); // Process that launch the "curl" command | |
p.addParameter("http://yourawesomewebsitethatreturnsplaintext.com"); // Add the URL parameter to "curl" | |
p.run(); // Run the process and wait for its termination | |
int j = 0; | |
while (p.available() > 0) { | |
char d = p.read(); | |
c[j] = d; | |
j++; | |
} | |
c[j] = 0; // null terminate string | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment