mirror of
https://github.com/digistump/DigistumpArduino.git
synced 2025-04-27 15:19:02 -07:00
Add OLED library - update tiny wire libraries - add support for all PWM channels and PWM on pin 8
This commit is contained in:
parent
fb93846380
commit
52f444d221
@ -103,6 +103,11 @@ int digitalRead(uint8_t);
|
||||
int analogRead(uint8_t);
|
||||
void analogReference(uint8_t mode);
|
||||
void analogWrite(uint8_t, int);
|
||||
void pwmWrite(uint8_t, int);
|
||||
void pwmConnect(uint8_t);
|
||||
void pwmDisconnect(uint8_t);
|
||||
void pwmReset(void);
|
||||
|
||||
|
||||
unsigned long millis(void);
|
||||
unsigned long micros(void);
|
||||
@ -160,8 +165,8 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
|
||||
#define TIMER1B 4
|
||||
#define TIMER1D 5
|
||||
|
||||
#define CHANNELA 3; //TIMER1A
|
||||
#define CHANNELB 4; //TIMER1B
|
||||
#define CHANNELA 3 //TIMER1A
|
||||
#define CHANNELB 4 //TIMER1B
|
||||
|
||||
#include "pins_arduino.h"
|
||||
|
||||
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
Stream.h - base class for character-based streams.
|
||||
Copyright (c) 2010 David A. Mellis. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef Stream_h
|
||||
#define Stream_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Print.h"
|
||||
|
||||
class Stream : public Print
|
||||
{
|
||||
public:
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
};
|
||||
|
||||
#endif
|
@ -185,15 +185,15 @@ void analogWrite(uint8_t pin, int val)
|
||||
uint8_t timer = digitalPinToTimer(pin);
|
||||
|
||||
|
||||
/*
|
||||
if( timer == TIMER0B){
|
||||
// connect pwm to pin on timer 0, channel B
|
||||
sbi(TCCR0A, COM0B1);
|
||||
cbi(TCCR0A, COM0B0);
|
||||
OCR0B = val; // set pwm duty
|
||||
} else
|
||||
*/
|
||||
|
||||
if( timer == TIMER0A){
|
||||
// connect pwm to pin 8 on timer 0, channel A
|
||||
sbi(TCCR0A, COM0A1);
|
||||
cbi(TCCR0A, COM0A0);
|
||||
sbi(TCCR0A, WGM01);
|
||||
sbi(TCCR0A, WGM00);
|
||||
OCR0A = val; // set pwm duty
|
||||
} else
|
||||
|
||||
if( timer == TIMER1A){
|
||||
// connect pwm to pin on timer 1, channel A
|
||||
|
52
hardware/digistump/avr/libraries/DigisparkOLED/CHANGES.txt
Normal file
52
hardware/digistump/avr/libraries/DigisparkOLED/CHANGES.txt
Normal file
@ -0,0 +1,52 @@
|
||||
CHANGES
|
||||
|
||||
|
||||
2015-01-10 (nb)
|
||||
|
||||
Fixed and improved initialization. New and improved printing of text. Updated texts.
|
||||
|
||||
- Fixed initialization commands.
|
||||
- Implemented ssd1306_init more efficiently.
|
||||
- New functions ssd1306_send_command_start, ssd1306_send_command_stop.
|
||||
- Improved ssd1306_setpos, more efficient.
|
||||
- Reimplemented function ssd1306_char_f6x8 as improved ssd1306_char_font6x8 printing single characters only, added new ssd1306_string_font6x8 for printing strings.
|
||||
- The font8x16 functions and data moved to another file until properly implemented.
|
||||
- Added to the Make file ssd1306xled8x16 file.
|
||||
- Updated testing text displayed on the screen.
|
||||
|
||||
|
||||
2015-01-10 (nb)
|
||||
|
||||
Changed default pins for display, now PB0=SCL and PB1=SDA. Source code reformatting, improvements, edited comments.
|
||||
|
||||
- Changed default pins for connecting to the display for consistency with the built-in TWI interface, they are now PB0=SCL and PB1=SDA.
|
||||
- Source code, removed redundant initializations of variables.
|
||||
- Source code reformatting, edited comments.
|
||||
|
||||
|
||||
2015-01-10 (nb)
|
||||
|
||||
Fixed some warnings, variables renamed. The font16x16/Chinese stuff moved to other folders.
|
||||
|
||||
- Font variable ssd1306xled_font8X16 renamed to ssd1306xled_font8x16 for consistency. TODO: rename "ssd1306xled_font8x16" file as well.
|
||||
- Fixed ssd1306_draw_bmp prototype: added "const" to bitmap so it wont't generate warning.
|
||||
- Files related to font 16x16 (Chinese) moved to different folders: font16x16cn.h.
|
||||
- Functions and other code related to font 16x16 (Chinese) moved to different folders.
|
||||
- Source code reformatting, edited comments.
|
||||
|
||||
|
||||
2014-10-26 (gs)
|
||||
|
||||
Make project compile on gcc-avr - turn static images to consts, and rename include of font16x16cn.h
|
||||
|
||||
|
||||
2014-08-13 (nb)
|
||||
|
||||
More files added to the repository.
|
||||
|
||||
|
||||
2014-08-11 (nb)
|
||||
|
||||
Files added to the repository.
|
||||
|
||||
|
231
hardware/digistump/avr/libraries/DigisparkOLED/DigisparkOLED.cpp
Normal file
231
hardware/digistump/avr/libraries/DigisparkOLED/DigisparkOLED.cpp
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
|
||||
*
|
||||
* @created: 2014-08-12
|
||||
* @author: Neven Boyanov
|
||||
*
|
||||
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
|
||||
*
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include "DigisparkOLED.h"
|
||||
#include "font6x8.h"
|
||||
#include "font8x16.h"
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Some code based on "IIC_wtihout_ACK" by http://www.14blog.com/archives/1358
|
||||
|
||||
const uint8_t ssd1306_init_sequence [] PROGMEM = { // Initialization Sequence
|
||||
0xAE, // Display OFF (sleep mode)
|
||||
0x20, 0b00, // Set Memory Addressing Mode
|
||||
// 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
|
||||
// 10=Page Addressing Mode (RESET); 11=Invalid
|
||||
0xB0, // Set Page Start Address for Page Addressing Mode, 0-7
|
||||
0xC8, // Set COM Output Scan Direction
|
||||
0x00, // ---set low column address
|
||||
0x10, // ---set high column address
|
||||
0x40, // --set start line address
|
||||
0x81, 0x3F, // Set contrast control register
|
||||
0xA1, // Set Segment Re-map. A0=address mapped; A1=address 127 mapped.
|
||||
0xA6, // Set display mode. A6=Normal; A7=Inverse
|
||||
0xA8, 0x3F, // Set multiplex ratio(1 to 64)
|
||||
0xA4, // Output RAM to Display
|
||||
// 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
|
||||
0xD3, 0x00, // Set display offset. 00 = no offset
|
||||
0xD5, // --set display clock divide ratio/oscillator frequency
|
||||
0xF0, // --set divide ratio
|
||||
0xD9, 0x22, // Set pre-charge period
|
||||
0xDA, 0x12, // Set com pins hardware configuration
|
||||
0xDB, // --set vcomh
|
||||
0x20, // 0x20,0.77xVcc
|
||||
0x8D, 0x14, // Set DC-DC enable
|
||||
0xAF // Display ON in normal mode
|
||||
|
||||
};
|
||||
|
||||
uint8_t oledFont, oledX, oledY = 0;
|
||||
|
||||
// Program: 5248 bytes
|
||||
|
||||
SSD1306Device::SSD1306Device(void){}
|
||||
|
||||
|
||||
void SSD1306Device::begin(void)
|
||||
{
|
||||
Wire.begin();
|
||||
|
||||
for (uint8_t i = 0; i < sizeof (ssd1306_init_sequence); i++) {
|
||||
ssd1306_send_command(pgm_read_byte(&ssd1306_init_sequence[i]));
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
void SSD1306Device::setFont(uint8_t font)
|
||||
{
|
||||
oledFont = font;
|
||||
}
|
||||
|
||||
void SSD1306Device::ssd1306_send_command_start(void) {
|
||||
Wire.beginTransmission(SSD1306);
|
||||
Wire.write(0x00); // write command
|
||||
}
|
||||
|
||||
void SSD1306Device::ssd1306_send_command_stop(void) {
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
void SSD1306Device::ssd1306_send_data_byte(uint8_t byte)
|
||||
{
|
||||
if(Wire.writeAvailable()){
|
||||
ssd1306_send_data_stop();
|
||||
ssd1306_send_data_start();
|
||||
}
|
||||
Wire.write(byte);
|
||||
|
||||
}
|
||||
|
||||
void SSD1306Device::ssd1306_send_command(uint8_t command)
|
||||
{
|
||||
ssd1306_send_command_start();
|
||||
Wire.write(command);
|
||||
ssd1306_send_command_stop();
|
||||
}
|
||||
|
||||
void SSD1306Device::ssd1306_send_data_start(void)
|
||||
{
|
||||
Wire.beginTransmission(SSD1306);
|
||||
Wire.write(0x40); //write data
|
||||
}
|
||||
|
||||
void SSD1306Device::ssd1306_send_data_stop(void)
|
||||
{
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
void SSD1306Device::setCursor(uint8_t x, uint8_t y)
|
||||
{
|
||||
ssd1306_send_command_start();
|
||||
Wire.write(0xb0 + y);
|
||||
Wire.write(((x & 0xf0) >> 4) | 0x10); // | 0x10
|
||||
Wire.write((x & 0x0f) | 0x01); // | 0x01
|
||||
ssd1306_send_command_stop();
|
||||
oledX = x;
|
||||
oledY = y;
|
||||
}
|
||||
|
||||
void SSD1306Device::clear(void)
|
||||
{
|
||||
fill(0x00);
|
||||
}
|
||||
|
||||
void SSD1306Device::fill(uint8_t fill)
|
||||
{
|
||||
uint8_t m,n;
|
||||
for (m = 0; m < 8; m++)
|
||||
{
|
||||
ssd1306_send_command(0xb0 + m); // page0 - page1
|
||||
ssd1306_send_command(0x00); // low column start address
|
||||
ssd1306_send_command(0x10); // high column start address
|
||||
ssd1306_send_data_start();
|
||||
for (n = 0; n < 128; n++)
|
||||
{
|
||||
ssd1306_send_data_byte(fill);
|
||||
}
|
||||
ssd1306_send_data_stop();
|
||||
}
|
||||
setCursor(0, 0);
|
||||
}
|
||||
|
||||
size_t SSD1306Device::write(byte c) {
|
||||
uint8_t i = 0;
|
||||
uint8_t ci = c - 32;
|
||||
if(c == '\r')
|
||||
return 1;
|
||||
if(c == '\n'){
|
||||
if(oledFont == 0)
|
||||
setCursor(0, oledY+1);
|
||||
else
|
||||
setCursor(0, oledY+2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(oledFont == 0){
|
||||
if (oledX > 122)
|
||||
{
|
||||
oledX = 0;
|
||||
oledY++;
|
||||
setCursor(oledX, oledY);
|
||||
}
|
||||
|
||||
ssd1306_send_data_start();
|
||||
for (i= 0; i < 6; i++)
|
||||
{
|
||||
ssd1306_send_data_byte(pgm_read_byte(&ssd1306xled_font6x8[ci * 6 + i]));
|
||||
}
|
||||
ssd1306_send_data_stop();
|
||||
setCursor(oledX+6, oledY);
|
||||
}
|
||||
else{
|
||||
if (oledX > 120)
|
||||
{
|
||||
oledX = 0;
|
||||
oledY++;
|
||||
setCursor(oledX, oledY);
|
||||
}
|
||||
|
||||
ssd1306_send_data_start();
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
Wire.write(pgm_read_byte(&ssd1306xled_font8x16[ci * 16 + i]));
|
||||
}
|
||||
ssd1306_send_data_stop();
|
||||
setCursor(oledX, oledY + 1);
|
||||
ssd1306_send_data_start();
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
Wire.write(pgm_read_byte(&ssd1306xled_font8x16[ci * 16 + i + 8]));
|
||||
}
|
||||
ssd1306_send_data_stop();
|
||||
setCursor(oledX + 8, oledY - 1);
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SSD1306Device::bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[])
|
||||
{
|
||||
uint16_t j = 0;
|
||||
uint8_t y, x;
|
||||
if (y1 % 8 == 0) y = y1 / 8;
|
||||
else y = y1 / 8 + 1;
|
||||
for (y = y0; y < y1; y++)
|
||||
{
|
||||
setCursor(x0,y);
|
||||
ssd1306_send_data_start();
|
||||
for (x = x0; x < x1; x++)
|
||||
{
|
||||
ssd1306_send_data_byte(pgm_read_byte(&bitmap[j++]));
|
||||
}
|
||||
ssd1306_send_data_stop();
|
||||
}
|
||||
setCursor(0, 0);
|
||||
}
|
||||
|
||||
|
||||
SSD1306Device oled;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
|
||||
*
|
||||
* @created: 2014-08-12
|
||||
* @author: Neven Boyanov
|
||||
*
|
||||
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
// #include <avr/pgmspace.h>
|
||||
// #include <avr/interrupt.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#ifndef DIGISPARKOLED_H
|
||||
#define DIGISPARKOLED_H
|
||||
|
||||
#define FONT8X16 1
|
||||
#define FONT6X8 0
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef SSD1306
|
||||
#define SSD1306 0x3C // Slave address
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class SSD1306Device: public Print {
|
||||
|
||||
public:
|
||||
SSD1306Device(void);
|
||||
void begin(void);
|
||||
void setFont(uint8_t font);
|
||||
void ssd1306_send_command(uint8_t command);
|
||||
void ssd1306_send_data_byte(uint8_t byte);
|
||||
void ssd1306_send_data_start(void);
|
||||
void ssd1306_send_data_stop(void);
|
||||
void setCursor(uint8_t x, uint8_t y);
|
||||
void fill(uint8_t fill);
|
||||
void clear(void);
|
||||
void bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]);
|
||||
void ssd1306_send_command_start(void);
|
||||
void ssd1306_send_command_stop(void);
|
||||
void ssd1306_char_f8x16(uint8_t x, uint8_t y, const char ch[]);
|
||||
virtual size_t write(byte c);
|
||||
using Print::write;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern SSD1306Device oled;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#endif
|
11
hardware/digistump/avr/libraries/DigisparkOLED/README.txt
Normal file
11
hardware/digistump/avr/libraries/DigisparkOLED/README.txt
Normal file
@ -0,0 +1,11 @@
|
||||
Overhauled to support Wire library, print library, and generally be more "Arduino friendly" - renamed DigiOLED to avoid confussion - 1/14/2015 by Erik Kettenburg/Digistump
|
||||
|
||||
Ported to Arduino CPP and working on DigiStump Pro 1/11/15 by defragster
|
||||
|
||||
SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
|
||||
|
||||
SSD1306xLED is a C library for working with the SSD1306 display driver to control dot matrix OLED/PLED 128x64 displays. It is intended to be used with the Tinusaur board but should also work with any other board based on ATtiny85 or similar microcontroller.
|
||||
|
||||
SSD1306xLED is written in plain C and does not require any additional libraries to function except those that come with the WinAVR SDK.
|
||||
|
||||
|
28
hardware/digistump/avr/libraries/DigisparkOLED/RESEARCH.txt
Normal file
28
hardware/digistump/avr/libraries/DigisparkOLED/RESEARCH.txt
Normal file
@ -0,0 +1,28 @@
|
||||
RESEARCH
|
||||
|
||||
|
||||
SSD1306
|
||||
http://www.solomon-systech.com/en/product/display-ic/oled-driver-controller/ssd1306/
|
||||
SSD1306 is a single-chip CMOS OLED/PLED driver with controller for organic / polymer light emitting diode dot-matrix graphic display system. It consists of 128 segments and 64 commons. This IC is designed for Common Cathode type OLED panel.
|
||||
|
||||
|
||||
---- SSD1306 Datasheets ----
|
||||
|
||||
https://www.adafruit.com/datasheets/SSD1306.pdf
|
||||
|
||||
http://www.crystalfontz.com/controllers/Solomon_Systech_SSD1306_v1.1_April_2008.pdf
|
||||
|
||||
|
||||
---- Other SSD1306 Libraries ----
|
||||
|
||||
|
||||
|
||||
---- Projects ----
|
||||
|
||||
|
||||
|
||||
---- Other References ----
|
||||
|
||||
|
||||
|
||||
|
6
hardware/digistump/avr/libraries/DigisparkOLED/TODO.txt
Normal file
6
hardware/digistump/avr/libraries/DigisparkOLED/TODO.txt
Normal file
@ -0,0 +1,6 @@
|
||||
TODO
|
||||
|
||||
|
||||
- Implement power saving mode
|
||||
|
||||
|
@ -0,0 +1,39 @@
|
||||
#include <DigisparkOLED.h>
|
||||
#include <Wire.h>
|
||||
// ============================================================================
|
||||
|
||||
#include "img0_128x64c1.h"
|
||||
#include "digistump_128x64c1.h"
|
||||
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
|
||||
oled.begin();
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// put your main code here, to run repeatedly:
|
||||
oled.fill(0xFF); //fill screen with color
|
||||
delay(1000);
|
||||
oled.clear(); //all black
|
||||
delay(1000);
|
||||
//usage: oled.setCursor(X IN PIXELS, Y IN ROWS OF 8 PIXELS STARTING WITH 0);
|
||||
oled.setCursor(0, 0); //top left
|
||||
oled.setFont(FONT8X16);
|
||||
oled.print(F("DIGISTUMP")); //wrap strings in F() to save RAM!
|
||||
oled.setFont(FONT6X8);
|
||||
oled.print(F(" OLED!"));
|
||||
oled.setCursor(0, 2); //two rows down because the 8x16 font takes two rows of 8
|
||||
oled.println(F("test")); //println will move the cursor 8 or 16 pixels down (based on the front) and back to X=0
|
||||
oled.print(F("test test test test test")); //lines auto wrap
|
||||
|
||||
delay(3000);
|
||||
//usage oled.bitmap(START X IN PIXELS, START Y IN ROWS OF 8 PIXELS, END X IN PIXELS, END Y IN ROWS OF 8 PIXELS, IMAGE ARRAY);
|
||||
oled.bitmap(0, 0, 128, 8, img0_128x64c1);
|
||||
delay(3000);
|
||||
oled.bitmap(0, 0, 128, 8, digistumplogo);
|
||||
delay(3000);
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File generated by LCD Assistant
|
||||
// http://en.radzio.dxp.pl/bitmap_converter/
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
|
||||
const uint8_t digistumplogo [] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xF0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
|
||||
0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF8, 0xF8, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xE0, 0xF0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xBF, 0xDF, 0xFF,
|
||||
0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0x0F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C,
|
||||
0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC,
|
||||
0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC,
|
||||
0xFC, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3F, 0xBF, 0x9F, 0xDF, 0xEF, 0xEF, 0xF7, 0xF7, 0xFB, 0xFD, 0xFD, 0xFE, 0xFF, 0x7F, 0x7F, 0x7F,
|
||||
0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x0F, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
|
||||
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x3F, 0x3F, 0x03, 0x03, 0x03, 0x03, 0x3F, 0x3F, 0x3F, 0x3F, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C,
|
||||
0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0x3C, 0x3C, 0x3C,
|
||||
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC,
|
||||
0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0xFC, 0xFC, 0xFC, 0xFC,
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1E,
|
||||
0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFE, 0xFE, 0xE0, 0xE0, 0xE0, 0xE0, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
|
||||
0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
|
||||
0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F,
|
||||
0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F,
|
||||
0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E,
|
||||
0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E,
|
||||
0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E,
|
||||
0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F,
|
||||
0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
@ -0,0 +1,76 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File generated by LCD Assistant
|
||||
// http://en.radzio.dxp.pl/bitmap_converter/
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const uint8_t img0_128x64c1 [] PROGMEM = {
|
||||
|
||||
0x00,0x03,0x05,0x09,0x11,0xFF,0x11,0x89,0x05,0xC3,0x00,0xE0,0x00,0xF0,0x00,0xF8,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x28,0xFF,0x11,0xAA,0x44,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x01,0x38,0x44,0x82,0x92,
|
||||
0x92,0x74,0x01,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x44,0xFF,0x01,0x7D,
|
||||
0x7D,0x7D,0x01,0x7D,0x7D,0x7D,0x7D,0x01,0x7D,0x7D,0x7D,0x7D,0x7D,0x01,0xFF,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,
|
||||
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x3F,0x03,0x03,
|
||||
0xF3,0x13,0x11,0x11,0x11,0x11,0x11,0x11,0x01,0xF1,0x11,0x61,0x81,0x01,0x01,0x01,
|
||||
0x81,0x61,0x11,0xF1,0x01,0x01,0x01,0x01,0x41,0x41,0xF1,0x01,0x01,0x01,0x01,0x01,
|
||||
0xC1,0x21,0x11,0x11,0x11,0x11,0x21,0xC1,0x01,0x01,0x01,0x01,0x41,0x41,0xF1,0x01,
|
||||
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x11,0x11,0x11,0x11,0x11,0xD3,0x33,
|
||||
0x03,0x03,0x3F,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xE0,0x00,0x00,
|
||||
0x7F,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x7F,0x00,0x00,0x01,0x06,0x18,0x06,
|
||||
0x01,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x40,0x40,0x7F,0x40,0x40,0x00,0x00,0x00,
|
||||
0x1F,0x20,0x40,0x40,0x40,0x40,0x20,0x1F,0x00,0x00,0x00,0x00,0x40,0x40,0x7F,0x40,
|
||||
0x40,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x40,0x30,0x0C,0x03,0x00,0x00,
|
||||
0x00,0x00,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x06,0x06,
|
||||
0x06,0x06,0x04,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,0x04,0x84,0x44,0x44,0x44,
|
||||
0x84,0x04,0x04,0x04,0x84,0xC4,0x04,0x04,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,
|
||||
0x04,0x04,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,0x04,0x04,0x04,0x04,0x84,0x44,
|
||||
0x44,0x44,0x84,0x04,0x04,0x84,0x44,0x44,0x44,0x84,0x04,0x04,0x04,0x04,0x06,0x06,
|
||||
0x06,0x06,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x10,0x18,0x14,0x12,0x11,0x00,0x00,0x0F,0x10,0x10,0x10,
|
||||
0x0F,0x00,0x00,0x00,0x10,0x1F,0x10,0x00,0x00,0x00,0x08,0x10,0x12,0x12,0x0D,0x00,
|
||||
0x00,0x18,0x00,0x00,0x0D,0x12,0x12,0x12,0x0D,0x00,0x00,0x18,0x00,0x00,0x10,0x18,
|
||||
0x14,0x12,0x11,0x00,0x00,0x10,0x18,0x14,0x12,0x11,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,
|
||||
0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x7F,0x03,0x0C,0x30,0x0C,0x03,0x7F,0x00,0x00,0x38,0x54,0x54,0x58,0x00,0x00,
|
||||
0x7C,0x04,0x04,0x78,0x00,0x00,0x3C,0x40,0x40,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xAA,0xAA,0xAA,
|
||||
0x28,0x08,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x03,0x0C,0x30,0x0C,0x03,0x7F,
|
||||
0x00,0x00,0x26,0x49,0x49,0x49,0x32,0x00,0x00,0x7F,0x02,0x04,0x08,0x10,0x7F,0x00,
|
||||
};
|
113
hardware/digistump/avr/libraries/DigisparkOLED/font6x8.h
Normal file
113
hardware/digistump/avr/libraries/DigisparkOLED/font6x8.h
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
|
||||
*
|
||||
* @created: 2014-08-12
|
||||
* @author: Neven Boyanov
|
||||
*
|
||||
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
|
||||
*
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/* Standard ASCII 6x8 font */
|
||||
const uint8_t ssd1306xled_font6x8 [] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
|
||||
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
|
||||
0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
|
||||
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
|
||||
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
|
||||
0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
|
||||
0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
|
||||
0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
|
||||
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
|
||||
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
|
||||
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
|
||||
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
|
||||
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
|
||||
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
|
||||
0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
|
||||
0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
|
||||
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
|
||||
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
|
||||
0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
|
||||
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
|
||||
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
|
||||
0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
|
||||
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
|
||||
0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
|
||||
0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
|
||||
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
|
||||
0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
|
||||
0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
|
||||
0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
|
||||
0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
|
||||
0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
|
||||
0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
|
||||
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
|
||||
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
|
||||
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
|
||||
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
|
||||
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
|
||||
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
|
||||
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
|
||||
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
|
||||
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
|
||||
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
|
||||
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
|
||||
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
|
||||
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
|
||||
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
|
||||
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
|
||||
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
|
||||
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
|
||||
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
|
||||
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
|
||||
0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
|
||||
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
|
||||
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
|
||||
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
|
||||
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
|
||||
0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
|
||||
0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
|
||||
0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
|
||||
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
|
||||
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
|
||||
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
|
||||
0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
|
||||
0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
|
||||
0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
|
||||
0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
|
||||
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
|
||||
0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
|
||||
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
|
||||
0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
|
||||
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
|
||||
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
|
||||
0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
|
||||
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
|
||||
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
|
||||
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
|
||||
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
|
||||
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
|
||||
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
|
||||
0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
|
||||
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
|
||||
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
|
||||
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
|
||||
0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
|
||||
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
|
||||
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
|
||||
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
|
||||
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
|
||||
0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
|
||||
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
|
||||
0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z
|
||||
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // horiz lines
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
116
hardware/digistump/avr/libraries/DigisparkOLED/font8x16.h
Normal file
116
hardware/digistump/avr/libraries/DigisparkOLED/font8x16.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
|
||||
*
|
||||
* @created: 2014-08-12
|
||||
* @author: Neven Boyanov
|
||||
*
|
||||
* Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
|
||||
*
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/* Standard ASCII 8x16 font */
|
||||
const uint8_t ssd1306xled_font8x16 [] PROGMEM = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0
|
||||
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00, // ! 1
|
||||
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // " 2
|
||||
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00, // # 3
|
||||
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00, // $ 4
|
||||
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00, // % 5
|
||||
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10, // & 6
|
||||
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ' 7
|
||||
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00, // ( 8
|
||||
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00, // ) 9
|
||||
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00, // * 10
|
||||
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00, // + 11
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00, // , 12
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01, // - 13
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00, // . 14
|
||||
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00, // / 15
|
||||
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, // 0 16
|
||||
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // 1 17
|
||||
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00, // 2 18
|
||||
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00, // 3 19
|
||||
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00, // 4 20
|
||||
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00, // 5 21
|
||||
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00, // 6 22
|
||||
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00, // 7 23
|
||||
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00, // 8 24
|
||||
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00, // 9 25
|
||||
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00, // : 26
|
||||
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00, // ; 27
|
||||
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00, // < 28
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00, // = 29
|
||||
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00, // > 30
|
||||
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00, // ? 31
|
||||
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00, // @ 32
|
||||
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20, // A 33
|
||||
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00, // B 34
|
||||
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00, // C 35
|
||||
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00, // D 36
|
||||
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00, // E 37
|
||||
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00, // F 38
|
||||
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00, // G 39
|
||||
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20, // H 40
|
||||
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // I 41
|
||||
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00, // J 42
|
||||
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00, // K 43
|
||||
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00, // L 44
|
||||
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00, // M 45
|
||||
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00, // N 46
|
||||
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00, // O 47
|
||||
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00, // P 48
|
||||
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00, // Q 49
|
||||
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20, // R 50
|
||||
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00, // S 51
|
||||
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00, // T 52
|
||||
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00, // U 53
|
||||
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00, // V 54
|
||||
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00, // W 55
|
||||
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20, // X 56
|
||||
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00, // Y 57
|
||||
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00, // Z 58
|
||||
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00, // [ 59
|
||||
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00, // \ 60
|
||||
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00, // ] 61
|
||||
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^ 62
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, // _ 63
|
||||
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ` 64
|
||||
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20, // a 65
|
||||
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00, // b 66
|
||||
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00, // c 67
|
||||
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20, // d 68
|
||||
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00, // e 69
|
||||
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // f 70
|
||||
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00, // g 71
|
||||
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20, // h 72
|
||||
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // i 73
|
||||
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00, // j 74
|
||||
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00, // k 75
|
||||
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, // l 76
|
||||
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F, // m 77
|
||||
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20, // n 78
|
||||
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00, // o 79
|
||||
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00, // p 80
|
||||
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80, // q 81
|
||||
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00, // r 82
|
||||
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00, // s 83
|
||||
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00, // t 84
|
||||
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20, // u 85
|
||||
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00, // v 86
|
||||
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00, // w 87
|
||||
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00, // x 88
|
||||
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00, // y 89
|
||||
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00, // z 90
|
||||
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40, // { 91
|
||||
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00, // | 92
|
||||
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00, // } 93
|
||||
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~ 94
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
@ -17,7 +17,7 @@ This sequence uses:
|
||||
IMPORTANT:
|
||||
=========
|
||||
For this sketch, which is using <DigiUSB> library:
|
||||
1) Comment "#define RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT" in "arduino-1.xx\libraries\RcSeq.h".
|
||||
1) Comment "#define RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT" AND #define RC_SEQ_CONTROL_SUPPORT in "arduino-1.xx\libraries\RcSeq.h".
|
||||
This will disable the code to manage incoming RC pulses and save some flash memory.
|
||||
RC_SEQ_WITH_SHORT_ACTION_SUPPORT and RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT shall be defined
|
||||
2) Replace #define RING_BUFFER_SIZE 128 with #define RING_BUFFER_SIZE 32 in "arduino-1.xx\libraries\DigisparkUSB\DigiUSB.h".
|
||||
@ -38,17 +38,17 @@ static void ToggleLed(void); /* Declare Short Action: Toggle a LED */
|
||||
#include <RcSeq.h>
|
||||
#include <SoftRcPulseOut.h>
|
||||
|
||||
#define LED_PIN 1
|
||||
#define LED_PIN 1
|
||||
|
||||
/*****************************************************************/
|
||||
/* STEP #2: Enumeration of the servos used in the sequence */
|
||||
/*****************************************************************/
|
||||
enum {ROTATION_SERVO=0, UP_DOWN_SERVO , SERVO_NB};
|
||||
enum {ROTATION_SERVO=0, UP_DOWN_SERVO, SERVO_NB};
|
||||
|
||||
/*****************************************************************/
|
||||
/* STEP #3: Servos Digital Pins assignment */
|
||||
/*****************************************************************/
|
||||
#define UP_DOWN_SERVO_PIN 2
|
||||
#define UP_DOWN_SERVO_PIN 2
|
||||
/* /!\ Do not use Pin 3 (used by USB) /!\ */
|
||||
/* /!\ Do not use Pin 4 (used by USB) /!\ */
|
||||
#define ROTATION_SERVO_PIN 5
|
||||
@ -56,12 +56,12 @@ enum {ROTATION_SERVO=0, UP_DOWN_SERVO , SERVO_NB};
|
||||
/**************************************************************************************/
|
||||
/* STEP #4: Declaration of the angles of the servos for the different motions (in °) */
|
||||
/**************************************************************************************/
|
||||
#define UP_DOWN_ON_DECK_POS 120 /* Zodiac on the deck */
|
||||
#define UP_DOWN_ON_AIR_POS 180 /* Zodiac in the air */
|
||||
#define UP_DOWN_ON_SEA_POS 0 /* Zodiac at sea level */
|
||||
#define UP_DOWN_ON_DECK_POS 120 /* Zodiac on the deck */
|
||||
#define UP_DOWN_ON_AIR_POS 180 /* Zodiac in the air */
|
||||
#define UP_DOWN_ON_SEA_POS 0 /* Zodiac at sea level */
|
||||
|
||||
#define ROTATION_ABOVE_DECK_POS 90 /* crane at deck side */
|
||||
#define ROTATION_ABOVE_SEA_POS 0 /* crane at sea side */
|
||||
#define ROTATION_ABOVE_DECK_POS 90 /* crane at deck side */
|
||||
#define ROTATION_ABOVE_SEA_POS 0 /* crane at sea side */
|
||||
|
||||
|
||||
/***************************************************************************************************************************************/
|
||||
@ -80,26 +80,26 @@ Order <--DECK_TO_AIR_DURATION_MS--> <--DECK_TO_SEA_ROTATION_DUR
|
||||
/* STEP #6: With the help of the temporal diagram, declare start up time, the motion duration of servo and optional delay */
|
||||
/**************************************************************************************************************************************************/
|
||||
/* Tune below all the motion duration. Do not forget to add a trailer 'UL' for each value to force them in Unsigned Long type */
|
||||
#define START_UP_DECK_TO_AIR_MS 0UL /* 0 for immediate start up, but you can put a delay here. Ex: 2000UL, will delay the startup of the whole sequence after 2 seconds */
|
||||
#define DECK_TO_AIR_DURATION_MS 3000UL
|
||||
#define START_UP_DECK_TO_AIR_MS 0UL /* 0 for immediate start up, but you can put a delay here. Ex: 2000UL, will delay the startup of the whole sequence after 2 seconds */
|
||||
#define DECK_TO_AIR_DURATION_MS 3000UL
|
||||
|
||||
#define START_UP_DECK_TO_SEA_ROTATION_MS (START_UP_DECK_TO_AIR_MS + DECK_TO_AIR_DURATION_MS)
|
||||
#define DECK_TO_SEA_ROTATION_DURATION_MS 3000UL
|
||||
#define START_UP_DECK_TO_SEA_ROTATION_MS (START_UP_DECK_TO_AIR_MS + DECK_TO_AIR_DURATION_MS)
|
||||
#define DECK_TO_SEA_ROTATION_DURATION_MS 3000UL
|
||||
|
||||
#define START_UP_AIR_TO_SEA_FALLING_MS (START_UP_DECK_TO_SEA_ROTATION_MS + DECK_TO_SEA_ROTATION_DURATION_MS)
|
||||
#define AIR_TO_SEA_FALLING_DURATION_MS 9000UL
|
||||
#define START_UP_AIR_TO_SEA_FALLING_MS (START_UP_DECK_TO_SEA_ROTATION_MS + DECK_TO_SEA_ROTATION_DURATION_MS)
|
||||
#define AIR_TO_SEA_FALLING_DURATION_MS 9000UL
|
||||
|
||||
#define DELAY_BEFORE_RISING_UP_MS 6000UL
|
||||
#define DELAY_BEFORE_RISING_UP_MS 6000UL
|
||||
|
||||
#define START_UP_SEA_TO_AIR_RISING_MS (START_UP_AIR_TO_SEA_FALLING_MS + AIR_TO_SEA_FALLING_DURATION_MS + DELAY_BEFORE_RISING_UP_MS)
|
||||
#define SEA_TO_AIR_RISING_DURATION_MS 9000UL
|
||||
#define START_UP_SEA_TO_AIR_RISING_MS (START_UP_AIR_TO_SEA_FALLING_MS + AIR_TO_SEA_FALLING_DURATION_MS + DELAY_BEFORE_RISING_UP_MS)
|
||||
#define SEA_TO_AIR_RISING_DURATION_MS 9000UL
|
||||
|
||||
#define START_UP_SEA_TO_DECK_ROTATION_MS (START_UP_SEA_TO_AIR_RISING_MS + SEA_TO_AIR_RISING_DURATION_MS)
|
||||
#define SEA_TO_DECK_ROTATION_DURATION_MS 3000UL
|
||||
#define START_UP_SEA_TO_DECK_ROTATION_MS (START_UP_SEA_TO_AIR_RISING_MS + SEA_TO_AIR_RISING_DURATION_MS)
|
||||
#define SEA_TO_DECK_ROTATION_DURATION_MS 3000UL
|
||||
|
||||
|
||||
#define START_UP_AIR_TO_DECK_FALLING_MS (START_UP_SEA_TO_DECK_ROTATION_MS + SEA_TO_DECK_ROTATION_DURATION_MS)
|
||||
#define AIR_TO_DECK_FALLING_DURATION_MS 3000UL
|
||||
#define START_UP_AIR_TO_DECK_FALLING_MS (START_UP_SEA_TO_DECK_ROTATION_MS + SEA_TO_DECK_ROTATION_DURATION_MS)
|
||||
#define AIR_TO_DECK_FALLING_DURATION_MS 3000UL
|
||||
|
||||
/********************************************************************************************************************/
|
||||
/* STEP #7: Declare here the percentage of motion to be performed at half speed for servo start up and stop */
|
||||
@ -118,7 +118,7 @@ Order <--DECK_TO_AIR_DURATION_MS--> <--DECK_TO_SEA_ROTATION_DUR
|
||||
/* - Percentage of motion performed at half speed for servo start and servo stop (Soft start and Soft stop) */
|
||||
/* Note: START_STOP_PER_CENT not used (MOTION_WITHOUT_SOFT_START_AND_STOP() macro used) */
|
||||
/************************************************************************************************************/
|
||||
SequenceSt_t ZodiacSequence[] PROGMEM = {
|
||||
const SequenceSt_t ZodiacSequence[] PROGMEM = {
|
||||
SHORT_ACTION_TO_PERFORM(ToggleLed, START_UP_DECK_TO_AIR_MS) /* Switch ON the Led at the beginning of the sequence */
|
||||
SHORT_ACTION_TO_PERFORM(ToggleLed, START_UP_AIR_TO_DECK_FALLING_MS+AIR_TO_DECK_FALLING_DURATION_MS) /* Switch OFF the Led at the beginning of the sequence: You are not obliged to put this line at the end of the table */
|
||||
/* 1) The crane lifts the pneumatic Zodiac from the deck to the air and stops */
|
||||
@ -155,7 +155,7 @@ void setup()
|
||||
/**************************************************************************************************************************/
|
||||
/* STEP #11: declare the sequence command signal (0), the stick level (0), and the sequence to call */
|
||||
/**************************************************************************************************************************/
|
||||
RcSeq_DeclareCommandAndSequence(0, 0, RC_SEQUENCE(ZodiacSequence)); /* 0,0 since there's no RC command */
|
||||
RcSeq_DeclareCommandAndSequence(0, 0, RC_SEQUENCE(ZodiacSequence)); /* 0, 0 since there's no RC command */
|
||||
}
|
||||
|
||||
void loop()
|
||||
@ -172,12 +172,12 @@ char RxChar;
|
||||
/****************************************************************************************************************/
|
||||
if(DigiUSB.available())
|
||||
{
|
||||
RxChar=DigiUSB.read();
|
||||
if(RxChar=='g') /* Go ! */
|
||||
RxChar = DigiUSB.read();
|
||||
if(RxChar == 'g') /* Go ! */
|
||||
{
|
||||
RcSeq_LaunchSequence(ZodiacSequence);
|
||||
}
|
||||
if(RxChar=='t') /* Toggle LED ! */
|
||||
if(RxChar == 't') /* Toggle LED ! */
|
||||
{
|
||||
RcSeq_LaunchShortAction(ToggleLed); /* You can toggle LED during Servo Motion! */
|
||||
}
|
||||
@ -187,7 +187,7 @@ char RxChar;
|
||||
|
||||
static void ToggleLed(void)
|
||||
{
|
||||
static boolean Status=LOW;
|
||||
Status=!Status; /* Toggle Status */
|
||||
static boolean Status = LOW;
|
||||
Status = !Status; /* Toggle Status */
|
||||
digitalWrite(LED_PIN, Status);
|
||||
}
|
||||
}
|
||||
|
@ -81,11 +81,11 @@ enum {RC_CHANNEL, RC_CHANNEL_NB}; /* Here, as there is a single channel, we coul
|
||||
/* Declaration of the custom keyboard": the pulse width of the push buttons do not need to be equidistant */
|
||||
enum {PUSH_BUTTON1, PUSH_BUTTON2, PUSH_BUTTON3, PUSH_BUTTON4, PUSH_BUTTON5, PUSH_BUTTON_NBR};
|
||||
#define TOLERANCE 40 /* Tolerance +/- (in microseconds): CAUTION, no overlap allowed between 2 adjacent active areas . active area width = 2 x TOLERANCE (us) */
|
||||
KeyMap_t CustomKeyboard[] PROGMEM ={ {CENTER_VALUE_US(1100,TOLERANCE)}, /* PUSH_BUTTON1: +/-40 us */
|
||||
{CENTER_VALUE_US(1300,TOLERANCE)}, /* PUSH_BUTTON2: +/-40 us */
|
||||
{CENTER_VALUE_US(1500,TOLERANCE)}, /* PUSH_BUTTON3: +/-40 us */
|
||||
{CENTER_VALUE_US(1700,TOLERANCE)}, /* PUSH_BUTTON4: +/-40 us */
|
||||
{CENTER_VALUE_US(1900,TOLERANCE)}, /* PUSH_BUTTON5: +/-40 us */
|
||||
const KeyMap_t CustomKeyboard[] PROGMEM ={ {CENTER_VALUE_US(1100,TOLERANCE)}, /* PUSH_BUTTON1: +/-40 us */
|
||||
{CENTER_VALUE_US(1300,TOLERANCE)}, /* PUSH_BUTTON2: +/-40 us */
|
||||
{CENTER_VALUE_US(1500,TOLERANCE)}, /* PUSH_BUTTON3: +/-40 us */
|
||||
{CENTER_VALUE_US(1700,TOLERANCE)}, /* PUSH_BUTTON4: +/-40 us */
|
||||
{CENTER_VALUE_US(1900,TOLERANCE)}, /* PUSH_BUTTON5: +/-40 us */
|
||||
};
|
||||
|
||||
//==============================================================================================
|
||||
|
@ -0,0 +1,307 @@
|
||||
/*
|
||||
This sketch illustrates 2 new features of the <RcSeq> library (since the V2.1 version):
|
||||
1) the "control" capability: it's a function passed as argument to the RcSeq_DeclareCommandAndSequence() method.
|
||||
It is used to check if a sequence can be launched or not, depending of specific condition
|
||||
It is also used to inform the sequence is finished: this can be used to memorize in EEPROM the sequence id.
|
||||
Like that, at the next start-up the position of the servos can be restored according to the last position of the sequence.
|
||||
2) the "timeout" capability:
|
||||
The RcSeq_Timeout() method can be used to check if the command signal remains constant (HIGH or LOW).
|
||||
It's then possible to launch the sequence based on the static state of the command pin rather than a Rc Pulse width.
|
||||
In practice, it's possible to use both manners to launch a sequence as done in the sketch below.
|
||||
|
||||
THE SKETCH:
|
||||
==========
|
||||
In this sketch, the first declared sequence opens the 2 doors with the help of 2 servos (1 per door).
|
||||
The second declared sequence closes the 2 doors with the help of 2 servos (1 per door).
|
||||
The 2 doors cannot open or close simultaneously with the same speed since there is a nosing secured to the right door.
|
||||
This nosing forces to open and close the doors using sequences.
|
||||
|
||||
Opening <- -> Opening
|
||||
. .
|
||||
. .
|
||||
. .
|
||||
. .
|
||||
. .
|
||||
. .
|
||||
. .
|
||||
__ nosing -> .------. __
|
||||
/ \----------------'---. '----------------/ \
|
||||
\__/-------------------''-------------------\__/
|
||||
Left door Right door
|
||||
TOP VIEW
|
||||
|
||||
The opening sequence is like hereafter:
|
||||
======================================
|
||||
1) The servo assigned to the right door starts
|
||||
2) Once rigth door slightly opened, the servo assigned to the left door starts, whilst the servo assigned to the right door resumes its travel
|
||||
3) Once the 2 servos reached 90°, the 2 doors stop; the opening sequence is finished
|
||||
|
||||
The closing sequence is like hereafter:
|
||||
======================================
|
||||
1) The 2 servos assigned to the left and right doors start together but the left servo rotates more quickly than the right servo.
|
||||
2) As a consequence, the left door is closed berfore the right door
|
||||
3) Once the 2 servos reached 90°, the 2 doors stop; the closing sequence is finished
|
||||
|
||||
The sequences of this sketch can be launched either a RC channel either a regular ON/OFF switch:
|
||||
===============================================================================================
|
||||
A) Command from a RC channel:
|
||||
------------------------- _______________
|
||||
V _______________ | __ |
|
||||
| __________ | ARDUINO: |________| / \ Left |
|
||||
| | | | | | \__/ Servo |
|
||||
| | RC |CH | UNO | |_______________|
|
||||
'-+ Receiver |----| MEGA | _______________
|
||||
| | | Digispark | | __ |
|
||||
|__________| | Digispark pro |________| / \ Right |
|
||||
|_______________| | \__/ Servo |
|
||||
|_______________|
|
||||
|
||||
B) Command from a ON/OFF switch:
|
||||
---------------------------- _______________
|
||||
_______________ | __ |
|
||||
| ARDUINO: |________| / \ Left |
|
||||
| | | \__/ Servo |
|
||||
| UNO | |_______________|
|
||||
.----| MEGA | _______________
|
||||
| | Digispark | | __ |
|
||||
ON/OFF Switch \ | Digispark pro |________| / \ Right |
|
||||
| |_______________| | \__/ Servo |
|
||||
-+- |_______________|
|
||||
GND
|
||||
*/
|
||||
|
||||
/*************************************************/
|
||||
/* STEP #1: Include the required libraries */
|
||||
/*************************************************/
|
||||
#include <RcSeq.h>
|
||||
#include <TinyPinChange.h>
|
||||
#include <SoftRcPulseIn.h>
|
||||
#include <SoftRcPulseOut.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
/*****************************************************************/
|
||||
/* STEP #2: Enumeration of the RC Signals used in the sequence */
|
||||
/*****************************************************************/
|
||||
enum {RC_SIGNAL = 0, SIGNAL_NB}; /* Here, a single RC signal is used */
|
||||
|
||||
/******************************************************************/
|
||||
/* STEP #3: Enumeration of the different position of the RC stick */
|
||||
/******************************************************************/
|
||||
enum {RC_PULSE_LEVEL_MINUS_1 = 0, RC_PULSE_LEVEL_PLUS_1, RC_PULSE_NB};
|
||||
|
||||
/*****************************************************************/
|
||||
/* STEP #4: Enumeration of the servos used in the sequences */
|
||||
/*****************************************************************/
|
||||
enum {DOOR_SERVO_LEFT = 0, DOOR_SERVO_RIGHT, SERVO_NB}; /* In this sketch, 2 servos are declared */
|
||||
|
||||
/***************************************************/
|
||||
/* STEP #5: Digital pin assignment for Command */
|
||||
/***************************************************/
|
||||
#define COMMAND_PIN 2 /* This pin can be connected to a channel of a RC Receiver or to a regular ON/OFF switch (switch wired between pin and Ground) */
|
||||
|
||||
/**************************************************/
|
||||
/* STEP #6: Digital Pins assignment for Servos */
|
||||
/**************************************************/
|
||||
#define DOOR_SERVO_LEFT_PIN 3
|
||||
#define DOOR_SERVO_RIGHT_PIN 4
|
||||
|
||||
/*************************************************************************************/
|
||||
/* STEP #7: Declaration of the angle of the servos for the different motions (in °) */
|
||||
/*************************************************************************************/
|
||||
#define DOOR_SERVO_OPENED_LEFT_POS 135 /* position of the left Servo when left door is opened */
|
||||
#define DOOR_SERVO_CLOSED_LEFT_POS 45 /* position of the left Servo when left door is closed */
|
||||
|
||||
#define DOOR_SERVO_OPENED_RIGHT_POS 45 /* position of the right Servo when right door is opened */
|
||||
#define DOOR_SERVO_CLOSED_RIGHT_POS 135 /* position of the right Servo when right door is closed */
|
||||
|
||||
|
||||
/***************************************************************************************************************************************/
|
||||
/* STEP #8: Do a temporal diagram showing the start up and the duration of each motions of each servo */
|
||||
/***************************************************************************************************************************************/
|
||||
/*
|
||||
1) OPENING MOTION OF THE DOORS
|
||||
===========================
|
||||
All the start up values (time stamp) have as reference the moment of the sequence startup order (t=0).
|
||||
|
||||
1.1 MOTION OF THE LEFT DOOR SERVO FOR OPENING
|
||||
=========================================
|
||||
|
||||
Order <---OPENING_DURATION_LEFT_MS--->
|
||||
|-----------------------------|--------------------------------|-->Time Axis
|
||||
0 OPENING_START_LEFT_MS
|
||||
|
||||
1.2 MOTION OF THE RIGHT DOOR SERVO FOR OPENING
|
||||
==========================================
|
||||
|
||||
Order <--------OPENING_DURATION_RIGHT_MS------->
|
||||
|-------------------|------------------------------------------|-->Time Axis
|
||||
0 OPENING_START_RIGHT_MS
|
||||
|
||||
|
||||
2) CLOSING MOTION OF THE DOORS
|
||||
===========================
|
||||
All the start up values (time stamp) have as reference the moment of the sequence startup order (t=0).
|
||||
|
||||
2.1 MOTION OF THE LEFT DOOR SERVO FOR CLOSING
|
||||
=========================================
|
||||
|
||||
Order <---CLOSING_DURATION_LEFT_MS--->
|
||||
|-------------------|--------------------------------|------------>Time Axis
|
||||
0 CLOSING_START_LEFT_MS
|
||||
|
||||
2.2 MOTION OF THE RIGTH DOOR SERVO FOR CLOSING
|
||||
==========================================
|
||||
|
||||
Order <--------CLOSING_DURATION_RIGHT_MS------->
|
||||
|-------------------|------------------------------------------|-->Time Axis
|
||||
0 CLOSING_START_RIGHT_MS
|
||||
*/
|
||||
|
||||
/**************************************************************************************************************************************************/
|
||||
/* STEP #9: With the help of the temporal diagram, declare start up time, the motion duration of servo and optional delay */
|
||||
/**************************************************************************************************************************************************/
|
||||
/* Tune below all the motion duration. Do not forget to add a trailer 'UL' for each value to force them in Unsigned Long type */
|
||||
#define OPENING_START_LEFT_MS 500UL //This means the left servo motion will be delayed of 500ms AFTER the order
|
||||
#define OPENING_DURATION_LEFT_MS 2500UL //The left door motion ends after 500+2500=3s, as the right door
|
||||
|
||||
#define OPENING_START_RIGHT_MS 0UL //Immediate start
|
||||
#define OPENING_DURATION_RIGHT_MS 3000UL //The right door motion ends after 3s
|
||||
|
||||
#define CLOSING_START_LEFT_MS 0UL //Immediate start
|
||||
#define CLOSING_DURATION_LEFT_MS 3000UL //The left door will be closed BEFORE the right door
|
||||
|
||||
#define CLOSING_START_RIGHT_MS 0UL //Immediate start
|
||||
#define CLOSING_DURATION_RIGHT_MS 4000UL //The right door will be closed AFTER the left door
|
||||
|
||||
/********************************************************************************************************************/
|
||||
/* STEP #10: Declare here the percentage of motion to be performed at half speed for servo start up and stop */
|
||||
/********************************************************************************************************************/
|
||||
#define START_STOP_PER_CENT 5 /* Percentage of motion performed at half-speed for starting and stopping the servos (Soft start et Soft stop) */
|
||||
|
||||
/************************************************************************************************************/
|
||||
/* STEP #11: Use a "const SequenceSt_t" structure table to declare the servo sequence */
|
||||
/* For each table entry, arguments are: */
|
||||
/* - Servo Index */
|
||||
/* - Initial Servo Position in ° */
|
||||
/* - Final Servo Position in ° */
|
||||
/* - Motion Start Time Stamp in ms */
|
||||
/* - Motion duration in ms between initial and final position */
|
||||
/* - Percentage of motion performed at half speed for servo start and servo stop (Soft start and Soft stop) */
|
||||
/************************************************************************************************************/
|
||||
/* Table describing the motions of the 2 servos for opening the 2 doors */
|
||||
const SequenceSt_t OpeningSequence[] PROGMEM = {/* Servo Id , Initial Angle , Final Angle , Delay after order , Motion Duration , Percentage at half speed */
|
||||
/* 1st Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_LEFT, DOOR_SERVO_CLOSED_LEFT_POS, DOOR_SERVO_OPENED_LEFT_POS, OPENING_START_LEFT_MS, OPENING_DURATION_LEFT_MS, START_STOP_PER_CENT)
|
||||
/* 2nd Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_RIGHT, DOOR_SERVO_CLOSED_RIGHT_POS, DOOR_SERVO_OPENED_RIGHT_POS, OPENING_START_RIGHT_MS, OPENING_DURATION_RIGHT_MS, START_STOP_PER_CENT)
|
||||
};
|
||||
|
||||
/* Table describing the motions of the 2 servos for closing the 2 doors */
|
||||
const SequenceSt_t ClosingSequence[] PROGMEM = {/* Servo Id , Initial Angle , Final Angle , Delai after order , Motion Duration , Percentage at half speed */
|
||||
/* 1st Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_LEFT, DOOR_SERVO_OPENED_LEFT_POS, DOOR_SERVO_CLOSED_LEFT_POS, CLOSING_START_LEFT_MS, CLOSING_DURATION_LEFT_MS, START_STOP_PER_CENT)
|
||||
/* 2nd Servo */ MOTION_WITH_SOFT_START_AND_STOP(DOOR_SERVO_RIGHT, DOOR_SERVO_OPENED_RIGHT_POS, DOOR_SERVO_CLOSED_RIGHT_POS, CLOSING_START_RIGHT_MS, CLOSING_DURATION_RIGHT_MS, START_STOP_PER_CENT)
|
||||
};
|
||||
|
||||
enum {COMMAND_OPEN = 0, COMMAND_CLOSE};
|
||||
|
||||
/* GLOBAL VARIABLES */
|
||||
uint8_t LastExecutedSeqIdx;
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny167__)
|
||||
Serial.begin(9600);
|
||||
Serial.print(F("RcSeq library V"));Serial.print(RcSeq_LibTextVersionRevision());Serial.println(F(" demo: advanced doors sequences"));
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
/* STEP #12: Init <RcSeq> library */
|
||||
/***************************************************************************/
|
||||
RcSeq_Init();
|
||||
|
||||
/****************************************************************************************/
|
||||
/* STEP #13: declare the servo command signals with their digital pin number */
|
||||
/****************************************************************************************/
|
||||
RcSeq_DeclareSignal(RC_SIGNAL, COMMAND_PIN);
|
||||
|
||||
/******************************************************************************************/
|
||||
/* STEP #14: declare a stick assigned to the RC signal having RC_PULSE_NB positions */
|
||||
/******************************************************************************************/
|
||||
RcSeq_DeclareStick(RC_SIGNAL, 1000, 2000, RC_PULSE_NB);
|
||||
|
||||
/****************************************************************************************/
|
||||
/* STEP #15: declare the servo command signals with their digital pin number */
|
||||
/****************************************************************************************/
|
||||
RcSeq_DeclareServo(DOOR_SERVO_LEFT, DOOR_SERVO_LEFT_PIN);
|
||||
RcSeq_DeclareServo(DOOR_SERVO_RIGHT, DOOR_SERVO_RIGHT_PIN);
|
||||
|
||||
/*******************************************************************************************************/
|
||||
/* STEP #16: declare the sequence assigned to specific position of the stick assigned to the RC signal */
|
||||
/*******************************************************************************************************/
|
||||
RcSeq_DeclareCommandAndSequence(RC_SIGNAL, RC_PULSE_LEVEL_MINUS_1, RC_SEQUENCE(OpeningSequence), Control); // Declare a sequence triggered by a RC pulse Level Minus 1 (stick at extreme position during at least 250 ms)
|
||||
RcSeq_DeclareCommandAndSequence(RC_SIGNAL, RC_PULSE_LEVEL_PLUS_1, RC_SEQUENCE(ClosingSequence), Control); // Declare a sequence triggered by a RC pulse Level Plus 1 (stick at extreme position during at least 250 ms)
|
||||
|
||||
/*******************************************************************************************/
|
||||
/* STEP #17: Initialize the position of the servos according to the last finished sequence */
|
||||
/*******************************************************************************************/
|
||||
LastExecutedSeqIdx = EEPROM.read(0);
|
||||
if (LastExecutedSeqIdx == COMMAND_OPEN)
|
||||
{
|
||||
RcSeq_ServoWrite(DOOR_SERVO_LEFT, DOOR_SERVO_OPENED_LEFT_POS);
|
||||
RcSeq_ServoWrite(DOOR_SERVO_RIGHT, DOOR_SERVO_OPENED_RIGHT_POS);
|
||||
}
|
||||
else
|
||||
{
|
||||
RcSeq_ServoWrite(DOOR_SERVO_LEFT, DOOR_SERVO_CLOSED_LEFT_POS);
|
||||
RcSeq_ServoWrite(DOOR_SERVO_RIGHT, DOOR_SERVO_CLOSED_RIGHT_POS);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint8_t RcSignalPinState;
|
||||
/****************************************************************************************************************/
|
||||
/* STEP #18: call the refresh function inside the loop() to catch RC commands and to manage the servo positions */
|
||||
/****************************************************************************************************************/
|
||||
RcSeq_Refresh();
|
||||
|
||||
/*********************************************************************************************************/
|
||||
/* STEP #19: optionally, allow launching the Sequences ou Actions on Timeout (cmd with a regular switch) */
|
||||
/*********************************************************************************************************/
|
||||
if (RcSeq_SignalTimeout(RC_SIGNAL, 250, &RcSignalPinState))
|
||||
{
|
||||
/* Launch the"OpeningSequence" sequence if a LOW level is present during at least 250ms: this allows testing the sequence of servo without using a RC set, just using a regular switch */
|
||||
if((LastExecutedSeqIdx == COMMAND_CLOSE) && (RcSignalPinState == LOW))
|
||||
{
|
||||
RcSeq_LaunchSequence(OpeningSequence);
|
||||
}
|
||||
/* Launch the"ClosingSequence" sequence if a HIGH level is present during at least 250ms: this allows testing the sequence of servo without using a RC set, just using a regular switch */
|
||||
if((LastExecutedSeqIdx == COMMAND_OPEN) && (RcSignalPinState == HIGH))
|
||||
{
|
||||
RcSeq_LaunchSequence(ClosingSequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The Control() fonction is automatically called by the RcSeq library */
|
||||
uint8_t Control(uint8_t Action, uint8_t SeqIdx)
|
||||
{
|
||||
uint8_t Ret = 0;
|
||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny167__)
|
||||
Serial.print("Action=");Serial.print(Action);Serial.print(" SeqIdx=");Serial.println(SeqIdx);
|
||||
#endif
|
||||
switch(Action)
|
||||
{
|
||||
case RC_SEQ_START_CONDITION: /* RcSeq asks if the conditions are met to launch the sequence SeqIdx */
|
||||
/* Put here a condition to allow RcSeq launching the sequence SeqIdx (Put Ret=1 if no specific condition) */
|
||||
Ret = (SeqIdx != LastExecutedSeqIdx); /* Allows RcSeq launching the sequence if the sequence to launch is different from the last one */
|
||||
break;
|
||||
|
||||
case RC_SEQ_END_OF_SEQ: /* RcSeq informs the sequence SeqIdx is finished */
|
||||
/* We memorize the last finished sequence id in EEPROM memory. Like that, at next power-up, we will know how to position the servos ( done in the Setup() ) */
|
||||
EEPROM.write(0, SeqIdx);
|
||||
LastExecutedSeqIdx = SeqIdx;
|
||||
break;
|
||||
}
|
||||
return(Ret);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <RcSeq.h>
|
||||
#include <TinyPinChange.h> /* Ne pas oublier d'inclure la librairie <TinyPinChange> qui est utilisee par la librairie <RcSeq> */
|
||||
#include <SoftRcPulseIn.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseIn> qui est utilisee par la librairie <RcSeq> */
|
||||
#include <SoftRcPulseOut.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseOut> qui est utilisee par la librairie <RcSeq> */
|
||||
#include <TinyPinChange.h>
|
||||
#include <SoftRcPulseIn.h>
|
||||
#include <SoftRcPulseOut.h>
|
||||
|
||||
/*
|
||||
IMPORTANT:
|
||||
@ -25,16 +25,16 @@ enum {RC_VOIE1, RC_VOIE2, RC_VOIE3, NBR_VOIES_RC}; /* Declaration des voies */
|
||||
|
||||
enum {BP1, BP2, NBR_BP}; /* Declaration des Boutons-Poussoirs (On peut aller jusqu'à BP8) */
|
||||
|
||||
enum {POS_MINUS1, POS_PLUS1,NBR_POS}; /* Declaration des positions du Manche on peut aller de POS_MOINS2 à POS_PLUS2 (4 Positions actives Max)*/
|
||||
enum {POS_MINUS1, POS_PLUS1, NBR_POS}; /* Declaration des positions du Manche on peut aller de POS_MOINS2 à POS_PLUS2 (4 Positions actives Max)*/
|
||||
|
||||
|
||||
/* Declaration d'un clavier "Maison": les impulsions des Boutons-Poussoirs n'ont pas besoin d'etre equidistantes */
|
||||
enum {BP_MAISON1, BP_MAISON2, BP_MAISON3, NBR_BP_MAISON};
|
||||
#define TOLERANCE 40 /* Tolerance en + ou en - (en micro-seconde) */
|
||||
KeyMap_t ClavierMaison[] PROGMEM ={ {VALEUR_CENTRALE_US(1100,TOLERANCE)}, /* BP_MAISON1: 1100 +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1300,TOLERANCE)}, /* BP_MAISON2: 1300 +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1700,TOLERANCE)}, /* BP_MAISON3: 1700 +/-40 us */
|
||||
};
|
||||
const KeyMap_t ClavierMaison[] PROGMEM ={ {VALEUR_CENTRALE_US(1100, TOLERANCE)}, /* BP_MAISON1: 1100 +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1300, TOLERANCE)}, /* BP_MAISON2: 1300 +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1700, TOLERANCE)}, /* BP_MAISON3: 1700 +/-40 us */
|
||||
};
|
||||
|
||||
enum {AZIMUT=0, ELEVATION , NBR_SERVO}; /* Delaration de tous les servos, 2 dans cet exemple (On peut déclaer jusqu'à 8 servos) */
|
||||
|
||||
@ -80,23 +80,23 @@ enum {AZIMUT=0, ELEVATION , NBR_SERVO}; /* Delaration de tous les servos, 2 dans
|
||||
#define DEM_ARRET_POUR_CENT 5 /* Pourcentage du mouvement devant etre effectue a mi-vitesse pour demarrage servo et arret servo (Soft start et Soft stop) */
|
||||
|
||||
/* Declaration de la table de sequence des mouvements des servo et des actions courtes */
|
||||
SequenceSt_t SequenceServoEtActionCourte[] PROGMEM = {
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed,DEMARRAGE_MONTEE_PONT_HAUT_MS)
|
||||
const SequenceSt_t SequenceServoEtActionCourte[] PROGMEM = {
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed, DEMARRAGE_MONTEE_PONT_HAUT_MS)
|
||||
/* Montee du Zodiac du pont vers la position haute */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION,ELEVATION_POS_PONT,ELEVATION_POS_HAUT,DEMARRAGE_MONTEE_PONT_HAUT_MS,DUREE_MONTEE_PONT_HAUT_MS,DEM_ARRET_POUR_CENT)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION, ELEVATION_POS_PONT, ELEVATION_POS_HAUT, DEMARRAGE_MONTEE_PONT_HAUT_MS, DUREE_MONTEE_PONT_HAUT_MS, DEM_ARRET_POUR_CENT)
|
||||
/* Rotation Grue du pont vers la mer */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(AZIMUT,AZIMUT_POS_PONT,AZIMUT_POS_MER,DEMARRAGE_ROTATION_PONT_MER_MS,DUREE_ROTATION_PONT_MER_MS,DEM_ARRET_POUR_CENT)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(AZIMUT, AZIMUT_POS_PONT, AZIMUT_POS_MER, DEMARRAGE_ROTATION_PONT_MER_MS, DUREE_ROTATION_PONT_MER_MS, DEM_ARRET_POUR_CENT)
|
||||
/* Descente du Zodiac depuis la position haute vers la la mer */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION,ELEVATION_POS_HAUT,ELEVATION_POS_MER,DEMARRAGE_DESCENTE_HAUT_MER_MS,DUREE_DESCENTE_HAUT_MER_MS,DEM_ARRET_POUR_CENT)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed,DEMARRAGE_DESCENTE_HAUT_MER_MS+DUREE_DESCENTE_HAUT_MER_MS)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed,DEMARRAGE_MONTEE_MER_HAUT_MS)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION, ELEVATION_POS_HAUT, ELEVATION_POS_MER, DEMARRAGE_DESCENTE_HAUT_MER_MS, DUREE_DESCENTE_HAUT_MER_MS, DEM_ARRET_POUR_CENT)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed, DEMARRAGE_DESCENTE_HAUT_MER_MS + DUREE_DESCENTE_HAUT_MER_MS)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed, DEMARRAGE_MONTEE_MER_HAUT_MS)
|
||||
/* Montee du Zodiac de la mer vers la position haute */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION,ELEVATION_POS_MER,ELEVATION_POS_HAUT,DEMARRAGE_MONTEE_MER_HAUT_MS,DUREE_MONTEE_MER_HAUT_MS,DEM_ARRET_POUR_CENT)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION, ELEVATION_POS_MER, ELEVATION_POS_HAUT, DEMARRAGE_MONTEE_MER_HAUT_MS, DUREE_MONTEE_MER_HAUT_MS, DEM_ARRET_POUR_CENT)
|
||||
/* Rotation Grue de la mer vers le pont */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(AZIMUT,AZIMUT_POS_MER,AZIMUT_POS_PONT,DEMARRAGE_ROTATION_MER_PONT_MS,DUREE_ROTATION_MER_PONT_MS,DEM_ARRET_POUR_CENT)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(AZIMUT, AZIMUT_POS_MER, AZIMUT_POS_PONT, DEMARRAGE_ROTATION_MER_PONT_MS, DUREE_ROTATION_MER_PONT_MS, DEM_ARRET_POUR_CENT)
|
||||
/* Descente du Zodiac de la position haute vers le pont */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION,ELEVATION_POS_HAUT,ELEVATION_POS_PONT,DEMARRAGE_DESCENTE_HAUT_PONT_MS,DUREE_DESCENTE_HAUT_PONT_MS,DEM_ARRET_POUR_CENT)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed,DEMARRAGE_DESCENTE_HAUT_PONT_MS+DUREE_DESCENTE_HAUT_PONT_MS)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION, ELEVATION_POS_HAUT, ELEVATION_POS_PONT, DEMARRAGE_DESCENTE_HAUT_PONT_MS, DUREE_DESCENTE_HAUT_PONT_MS, DEM_ARRET_POUR_CENT)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed, DEMARRAGE_DESCENTE_HAUT_PONT_MS + DUREE_DESCENTE_HAUT_PONT_MS)
|
||||
};
|
||||
|
||||
#define LED 13
|
||||
@ -114,22 +114,22 @@ void setup()
|
||||
RcSeq_DeclareServo(AZIMUT, BROCHE_SIGNAL_SERVO_AZ);
|
||||
|
||||
/* Commande d'une action courte et d'une sequence de servos avec 2 BP du clavier de la VOIE1 */
|
||||
RcSeq_DeclareSignal(RC_VOIE1,BROCHE_SIGNAL_RECEPTEUR_VOIE1);
|
||||
RcSeq_DeclareSignal(RC_VOIE1, BROCHE_SIGNAL_RECEPTEUR_VOIE1);
|
||||
RcSeq_DeclareClavier(RC_VOIE1, 1000, 2000, NBR_BP);
|
||||
RcSeq_DeclareCommandeEtActionCourte(RC_VOIE1, BP1, InverseLed);
|
||||
RcSeq_DeclareCommandeEtSequence(RC_VOIE1, BP2, RC_SEQUENCE(SequenceServoEtActionCourte));
|
||||
RcSeq_DeclareCommandeEtSequence(RC_VOIE1, BP2, RC_SEQUENCE(SequenceServoEtActionCourte), NULL);
|
||||
|
||||
/* Commande d'une action courte et d'une sequence de servos avec le manche de la VOIE2 */
|
||||
RcSeq_DeclareSignal(RC_VOIE2,BROCHE_SIGNAL_RECEPTEUR_VOIE2);
|
||||
RcSeq_DeclareSignal(RC_VOIE2, BROCHE_SIGNAL_RECEPTEUR_VOIE2);
|
||||
RcSeq_DeclareManche(RC_VOIE2, 1000, 2000, NBR_POS);
|
||||
RcSeq_DeclareCommandeEtActionCourte(RC_VOIE2, POS_MINUS1, InverseLed);
|
||||
RcSeq_DeclareCommandeEtSequence(RC_VOIE2, POS_PLUS1, RC_SEQUENCE(SequenceServoEtActionCourte));
|
||||
RcSeq_DeclareCommandeEtSequence(RC_VOIE2, POS_PLUS1, RC_SEQUENCE(SequenceServoEtActionCourte), NULL);
|
||||
|
||||
/* Commande d'une action courte et d'une sequence de servos avec le clavier "maison" de la VOIE3 */
|
||||
RcSeq_DeclareSignal(RC_VOIE3,BROCHE_SIGNAL_RECEPTEUR_VOIE3);
|
||||
RcSeq_DeclareSignal(RC_VOIE3, BROCHE_SIGNAL_RECEPTEUR_VOIE3);
|
||||
RcSeq_DeclareClavierMaison(RC_VOIE3, RC_CLAVIER_MAISON(ClavierMaison));
|
||||
RcSeq_DeclareCommandeEtActionCourte(RC_VOIE3, BP_MAISON1, InverseLed);
|
||||
RcSeq_DeclareCommandeEtSequence(RC_VOIE3, BP_MAISON3, RC_SEQUENCE(SequenceServoEtActionCourte));
|
||||
RcSeq_DeclareCommandeEtSequence(RC_VOIE3, BP_MAISON3, RC_SEQUENCE(SequenceServoEtActionCourte), NULL);
|
||||
|
||||
pinMode(LED, OUTPUT);
|
||||
}
|
||||
@ -142,13 +142,13 @@ void loop()
|
||||
/* Action associee au BP1 de la VOIE1 ou au manche position basse de la VOIE2 ou au BP_MAISON1 de la VOIE3 */
|
||||
void InverseLed(void)
|
||||
{
|
||||
static uint32_t DebutMs=millis(); /* static, pour conserver l'etat entre 2 appels de la fonction */
|
||||
static boolean Etat=HIGH; /* static, pour conserver l'etat entre 2 appels de la fonction */
|
||||
static uint32_t DebutMs = millis(); /* static, pour conserver l'etat entre 2 appels de la fonction */
|
||||
static boolean Etat = HIGH; /* static, pour conserver l'etat entre 2 appels de la fonction */
|
||||
|
||||
if(millis() - DebutMs >= 500UL) /* Depuis RcSeq V2.0, la tempo inter-commande doit etre geree dans le sketch utilisateur */
|
||||
{
|
||||
DebutMs=millis();
|
||||
DebutMs = millis();
|
||||
digitalWrite(LED, Etat);
|
||||
Etat=!Etat; /* Au prochain appel de InverseLed(), l'etat de la LED sera inverse */
|
||||
Etat = !Etat; /* Au prochain appel de InverseLed(), l'etat de la LED sera inverse */
|
||||
}
|
||||
}
|
||||
|
@ -32,9 +32,9 @@ Cette sequence utilise:
|
||||
/* ETAPE N°1: Inclure les 4 librairies necessaires */
|
||||
/***************************************************/
|
||||
#include <RcSeq.h>
|
||||
#include <TinyPinChange.h> /* Ne pas oublier d'inclure la librairie <TinyPinChange> qui est utilisee par la librairie <RcSeq> */
|
||||
#include <SoftRcPulseIn.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseIn> qui est utilisee par la librairie <RcSeq> */
|
||||
#include <SoftRcPulseOut.h> /* Ne pas oublier d'inclure la librairie <SoftRcPulseOut> qui est utilisee par la librairie <RcSeq> */
|
||||
#include <TinyPinChange.h>
|
||||
#include <SoftRcPulseIn.h>
|
||||
#include <SoftRcPulseOut.h>
|
||||
|
||||
/*****************************************************/
|
||||
/* ETAPE N°2: Enumeration des signaux de commande RC */
|
||||
@ -121,23 +121,23 @@ Ordre <---DUREE_MONTEE_PONT_HAUT_MS--> <--DUREE_ROTATION_PONT_M
|
||||
/* Il est possible d'inclure des actions courtes. Il suffit d'utiliser la macro ACTION_COURTE_A_EFFECTUER() en donnant le nom de la fonction a appeler et le */
|
||||
/* moment ou l'action doit avoir lieu. Dans cet exemple, la LED s'allume pendant que les servos tournent et s'eteint pendant la pause de 6 secondes. */
|
||||
/***************************************************************************************************************************************************************/
|
||||
SequenceSt_t SequencePlus2[] PROGMEM = {
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed,DEMARRAGE_MONTEE_PONT_HAUT_MS)
|
||||
const SequenceSt_t SequencePlus2[] PROGMEM = {
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed, DEMARRAGE_MONTEE_PONT_HAUT_MS)
|
||||
/* Montee du Zodiac du pont vers la position haute */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION,ELEVATION_POS_PONT,ELEVATION_POS_HAUT,DEMARRAGE_MONTEE_PONT_HAUT_MS,DUREE_MONTEE_PONT_HAUT_MS,DEM_ARRET_POUR_CENT)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION, ELEVATION_POS_PONT, ELEVATION_POS_HAUT, DEMARRAGE_MONTEE_PONT_HAUT_MS, DUREE_MONTEE_PONT_HAUT_MS, DEM_ARRET_POUR_CENT)
|
||||
/* Rotation Grue du pont vers la mer */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(AZIMUT,AZIMUT_POS_PONT,AZIMUT_POS_MER,DEMARRAGE_ROTATION_PONT_MER_MS,DUREE_ROTATION_PONT_MER_MS,DEM_ARRET_POUR_CENT)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(AZIMUT, AZIMUT_POS_PONT, AZIMUT_POS_MER, DEMARRAGE_ROTATION_PONT_MER_MS, DUREE_ROTATION_PONT_MER_MS, DEM_ARRET_POUR_CENT)
|
||||
/* Descente du Zodiac depuis la position haute vers la la mer */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION,ELEVATION_POS_HAUT,ELEVATION_POS_MER,DEMARRAGE_DESCENTE_HAUT_MER_MS,DUREE_DESCENTE_HAUT_MER_MS,DEM_ARRET_POUR_CENT)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed,DEMARRAGE_DESCENTE_HAUT_MER_MS+DUREE_DESCENTE_HAUT_MER_MS)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed,DEMARRAGE_MONTEE_MER_HAUT_MS)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION, ELEVATION_POS_HAUT, ELEVATION_POS_MER, DEMARRAGE_DESCENTE_HAUT_MER_MS, DUREE_DESCENTE_HAUT_MER_MS, DEM_ARRET_POUR_CENT)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed, DEMARRAGE_DESCENTE_HAUT_MER_MS + DUREE_DESCENTE_HAUT_MER_MS)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed, DEMARRAGE_MONTEE_MER_HAUT_MS)
|
||||
/* Montee du Zodiac de la mer vers la position haute */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION,ELEVATION_POS_MER,ELEVATION_POS_HAUT,DEMARRAGE_MONTEE_MER_HAUT_MS,DUREE_MONTEE_MER_HAUT_MS,DEM_ARRET_POUR_CENT)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION, ELEVATION_POS_MER, ELEVATION_POS_HAUT, DEMARRAGE_MONTEE_MER_HAUT_MS, DUREE_MONTEE_MER_HAUT_MS, DEM_ARRET_POUR_CENT)
|
||||
/* Rotation Grue de la mer vers le pont */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(AZIMUT,AZIMUT_POS_MER,AZIMUT_POS_PONT,DEMARRAGE_ROTATION_MER_PONT_MS,DUREE_ROTATION_MER_PONT_MS,DEM_ARRET_POUR_CENT)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(AZIMUT, AZIMUT_POS_MER, AZIMUT_POS_PONT, DEMARRAGE_ROTATION_MER_PONT_MS, DUREE_ROTATION_MER_PONT_MS, DEM_ARRET_POUR_CENT)
|
||||
/* Descente du Zodiac de la position haute vers le pont */
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION,ELEVATION_POS_HAUT,ELEVATION_POS_PONT,DEMARRAGE_DESCENTE_HAUT_PONT_MS,DUREE_DESCENTE_HAUT_PONT_MS,DEM_ARRET_POUR_CENT)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed,DEMARRAGE_DESCENTE_HAUT_PONT_MS+DUREE_DESCENTE_HAUT_PONT_MS)
|
||||
MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS(ELEVATION, ELEVATION_POS_HAUT, ELEVATION_POS_PONT, DEMARRAGE_DESCENTE_HAUT_PONT_MS, DUREE_DESCENTE_HAUT_PONT_MS, DEM_ARRET_POUR_CENT)
|
||||
ACTION_COURTE_A_EFFECTUER(InverseLed, DEMARRAGE_DESCENTE_HAUT_PONT_MS + DUREE_DESCENTE_HAUT_PONT_MS)
|
||||
};
|
||||
|
||||
#define LED 13
|
||||
@ -158,7 +158,7 @@ void setup()
|
||||
/**************************************************************************************/
|
||||
/* ETAPE N°13: declarer le(s) signal(aux) de commande RC avec leur N° de pin digitale */
|
||||
/**************************************************************************************/
|
||||
RcSeq_DeclareSignal(SIGNAL_RC,BROCHE_SIGNAL_RECEPTEUR);
|
||||
RcSeq_DeclareSignal(SIGNAL_RC, BROCHE_SIGNAL_RECEPTEUR);
|
||||
|
||||
/******************************************************************************************/
|
||||
/* ETAPE N°14: que le signal RC est associe a un manche qui a NBR_RC_IMPULSIONS positions */
|
||||
@ -174,7 +174,7 @@ void setup()
|
||||
/**************************************************************************************************************************/
|
||||
/* ETAPE N°16: declarer le signal de commande de sequence, le niveau du manche, et la sequence ou action courte a appeler */
|
||||
/**************************************************************************************************************************/
|
||||
RcSeq_DeclareCommandeEtSequence(SIGNAL_RC, RC_IMPULSION_NIVEAU_PLUS_2, RC_SEQUENCE(SequencePlus2)); // Voici comment declarer une sequence actionnee par une impulsion Niveau Plus 2 (manche en position extreme pendant au moins 250 ms)
|
||||
RcSeq_DeclareCommandeEtSequence(SIGNAL_RC, RC_IMPULSION_NIVEAU_PLUS_2, RC_SEQUENCE(SequencePlus2), NULL); // Voici comment declarer une sequence actionnee par une impulsion Niveau Plus 2 (manche en position extreme pendant au moins 250 ms)
|
||||
|
||||
pinMode(LED, OUTPUT);
|
||||
RcSeq_DeclareCommandeEtActionCourte(SIGNAL_RC, RC_IMPULSION_NIVEAU_MOINS_1, InverseLed); // Voici comment declarer une action actionnee par une impulsion Niveau Moins 1 (manche en position mi-course pendant au moins 250 ms)
|
||||
|
@ -30,31 +30,31 @@ enum {RC_VOIE, NBR_VOIES_RC}; /* Ici, comme il n'y a qu'une voie, on aurait pu f
|
||||
/* Declaration d'un clavier "Maison": les impulsions des Boutons-Poussoirs n'ont pas besoin d'etre equidistantes */
|
||||
enum {BP1, BP2, BP3, BP4, BP5, BP6, BP7, BP8, NBR_BP};
|
||||
#define TOLERANCE 40 /* Tolerance en + ou en - (en micro-seconde): ATTENTION, il ne doit pas y avoir recouvrement entre 2 zones actives adjascentes. Zone active = 2 x TOLERANCE (us) */
|
||||
KeyMap_t ClavierMaison[] PROGMEM ={ {VALEUR_CENTRALE_US(1100,TOLERANCE)}, /* BP1: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1200,TOLERANCE)}, /* BP2: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1300,TOLERANCE)}, /* BP3: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1400,TOLERANCE)}, /* BP4: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1600,TOLERANCE)}, /* BP5: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1700,TOLERANCE)}, /* BP6: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1800,TOLERANCE)}, /* BP7: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1900,TOLERANCE)}, /* BP8: +/-40 us */
|
||||
};
|
||||
const KeyMap_t ClavierMaison[] PROGMEM ={ {VALEUR_CENTRALE_US(1100,TOLERANCE)}, /* BP1: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1200,TOLERANCE)}, /* BP2: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1300,TOLERANCE)}, /* BP3: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1400,TOLERANCE)}, /* BP4: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1600,TOLERANCE)}, /* BP5: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1700,TOLERANCE)}, /* BP6: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1800,TOLERANCE)}, /* BP7: +/-40 us */
|
||||
{VALEUR_CENTRALE_US(1900,TOLERANCE)}, /* BP8: +/-40 us */
|
||||
};
|
||||
|
||||
//==============================================================================================
|
||||
/* Astuce: une macro pour n'ecrire qu'une seule fois la fonction ActionX() */
|
||||
#define DECLARE_ACTION(Idx) \
|
||||
void Action##Idx(void) \
|
||||
{ \
|
||||
static uint32_t DebutMs=millis(); \
|
||||
static boolean Etat=HIGH; \
|
||||
static uint32_t DebutMs = millis(); \
|
||||
static boolean Etat = HIGH; \
|
||||
/* Depuis la version 2.0 de la lib <RcSeq>, pour */ \
|
||||
/* des raisons de reactivite, la tempo inter-commande */ \
|
||||
/* doit etre geree dans le sketch utilisateur. */ \
|
||||
if(millis() - DebutMs >= 500UL) \
|
||||
{ \
|
||||
DebutMs=millis(); \
|
||||
DebutMs = millis(); \
|
||||
digitalWrite(Idx, Etat); \
|
||||
Etat=!Etat; \
|
||||
Etat = !Etat; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "RcSeq.h"
|
||||
/*
|
||||
English: by RC Navy (2012/2013)
|
||||
English: by RC Navy (2012-2015)
|
||||
=======
|
||||
<RcSeq> is an asynchronous library for ATmega328P (UNO), ATtiny84 and ATtiny85 to easily create servo's sequences and/or to execute short actions from RC commands.
|
||||
It can also be used to trig some short "actions" (the duration must be less than 20ms to not disturb the servo commands)
|
||||
@ -21,7 +21,7 @@
|
||||
CAUTION: the end user shall also use asynchronous programmation method in the loop() function (no blocking functions such as delay() or pulseIn()).
|
||||
http://p.loussouarn.free.fr
|
||||
|
||||
Francais: par RC Navy (2012/2013)
|
||||
Francais: par RC Navy (2012-2015)
|
||||
========
|
||||
<RcSeq> est une librairie asynchrone pour ATmega328P (UNO), ATtiny84 et ATtiny85 pour creer facilement des sequences de servos et/ou executer des actions depuis des commandes RC.
|
||||
Elle peut egalement etre utilisee pour lancer des "actions courtes" (la duree doit etre inferieure a 20ms pour ne pas perturber la commande des servos)
|
||||
@ -58,7 +58,7 @@
|
||||
| | | \
|
||||
| X O X | --> RC_IMPULSION_NIVEAU_MOINS_1 |
|
||||
| | | |
|
||||
| X O X | --> RC_IMPULSION_NIVEAU_MOINS_2 |
|
||||
| X O X | --> RC_IMPULSION_NIVEAU_MOINS_2 |
|
||||
'---------------------' /
|
||||
| | | | |
|
||||
| | | | | \
|
||||
@ -76,6 +76,10 @@
|
||||
/*************************************************************************
|
||||
MACROS
|
||||
*************************************************************************/
|
||||
/* For an easy Library Version Management */
|
||||
#define RC_SEQ_LIB_VERSION 2
|
||||
#define RC_SEQ_LIB_REVISION 1
|
||||
|
||||
#define STR(s) #s
|
||||
#define MAKE_TEXT_VER_REV(Ver,Rev) (char*)(STR(Ver)"."STR(Rev))
|
||||
|
||||
@ -123,12 +127,12 @@ Pos 0 1 2 3 4
|
||||
1000us 2000us (Typical Pulse Width values)
|
||||
|
||||
*/
|
||||
#define ACTIVE_AREA_STEP_NBR 3
|
||||
#define INACTIVE_AREA_STEP_NBR 1
|
||||
#define TOTAL_STEP_NBR(KeyNb,Type) ((Type==RC_CMD_STICK)?((KeyNb)*(ACTIVE_AREA_STEP_NBR+INACTIVE_AREA_STEP_NBR)):(((KeyNb)*(ACTIVE_AREA_STEP_NBR+INACTIVE_AREA_STEP_NBR))-1))
|
||||
#define STEP(MinUs, MaxUs,KeyNb,Type) ((MaxUs-MinUs)/TOTAL_STEP_NBR(KeyNb,Type))
|
||||
#define KEY_MIN_VAL(Idx,Step) ((ACTIVE_AREA_STEP_NBR+INACTIVE_AREA_STEP_NBR)*(Step)*(Idx))
|
||||
#define KEY_MAX_VAL(Idx,Step) (KEY_MIN_VAL(Idx,Step)+(ACTIVE_AREA_STEP_NBR*(Step)))
|
||||
#define ACTIVE_AREA_STEP_NBR 3
|
||||
#define INACTIVE_AREA_STEP_NBR 1
|
||||
#define TOTAL_STEP_NBR(KeyNb, Type) ((Type==RC_CMD_STICK)?((KeyNb)*(ACTIVE_AREA_STEP_NBR+INACTIVE_AREA_STEP_NBR)):(((KeyNb)*(ACTIVE_AREA_STEP_NBR+INACTIVE_AREA_STEP_NBR))-1))
|
||||
#define STEP(MinUs, MaxUs, KeyNb, Type) ((MaxUs-MinUs)/TOTAL_STEP_NBR(KeyNb,Type))
|
||||
#define KEY_MIN_VAL(Idx, Step) ((ACTIVE_AREA_STEP_NBR+INACTIVE_AREA_STEP_NBR)*(Step)*(Idx))
|
||||
#define KEY_MAX_VAL(Idx, Step) (KEY_MIN_VAL(Idx,Step)+(ACTIVE_AREA_STEP_NBR*(Step)))
|
||||
|
||||
typedef struct {
|
||||
int8_t InProgress;
|
||||
@ -138,6 +142,9 @@ typedef struct {
|
||||
void *TableOrShortAction;
|
||||
uint8_t SequenceLength;
|
||||
uint8_t ShortActionMap;
|
||||
#ifdef RC_SEQ_CONTROL_SUPPORT
|
||||
uint8_t(*Control)(uint8_t Action, uint8_t SeqIdx);
|
||||
#endif
|
||||
}CmdSequenceSt_t;
|
||||
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
@ -147,14 +154,14 @@ typedef struct {
|
||||
}PosST_t;
|
||||
|
||||
typedef struct {
|
||||
SoftRcPulseIn Pulse;
|
||||
PosST_t Pos;
|
||||
uint8_t Type; /* RC_CMD_STICK or RC_CMD_KEYBOARD or RC_CMD_CUSTOM */
|
||||
uint8_t PosNb;
|
||||
uint16_t PulseMinUs;
|
||||
uint16_t PulseMaxUs;
|
||||
uint16_t StepUs;
|
||||
KeyMap_t *KeyMap;
|
||||
SoftRcPulseIn Pulse;
|
||||
PosST_t Pos;
|
||||
uint8_t Type; /* RC_CMD_STICK or RC_CMD_KEYBOARD or RC_CMD_CUSTOM */
|
||||
uint8_t PosNb;
|
||||
uint16_t PulseMinUs;
|
||||
uint16_t PulseMaxUs;
|
||||
uint16_t StepUs;
|
||||
const KeyMap_t *KeyMap;
|
||||
}RcCmdSt_t;
|
||||
#endif
|
||||
|
||||
@ -175,47 +182,42 @@ static uint8_t CmdSignalNb;
|
||||
static RcCmdSt_t RcChannel[RC_CMD_MAX_NB];
|
||||
#endif
|
||||
#ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
#define AsMember .
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
|
||||
static ServoSt_t Servo[SERVO_MAX_NB];
|
||||
#endif
|
||||
static CmdSequenceSt_t CmdSequence[SEQUENCE_MAX_NB];
|
||||
#else
|
||||
#define AsMember ->
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
|
||||
static ServoSt_t **Servo=NULL;
|
||||
static ServoSt_t *Servo = NULL;
|
||||
#endif
|
||||
static CmdSequenceSt_t **CmdSequence=NULL;
|
||||
static CmdSequenceSt_t *CmdSequence = NULL;
|
||||
#endif
|
||||
/*************************************************************************
|
||||
PRIVATE FUNCTION PROTOTYPES
|
||||
*************************************************************************/
|
||||
static void ExecuteSequence(uint8_t CmdIdx, uint8_t Pos);
|
||||
#ifndef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
static void LoadSequenceOrShortAction(uint8_t CmdIdx,uint8_t Pos,void *SequenceOrShortAction, uint8_t SequenceLength);
|
||||
#endif
|
||||
static uint8_t ExecuteSequence(uint8_t CmdIdx, uint8_t Pos);
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
static int8_t GetPos(uint8_t ChIdx,uint16_t PulseWidthUs);
|
||||
static int8_t GetPos(uint8_t ChIdx, uint16_t PulseWidthUs);
|
||||
#endif
|
||||
|
||||
//========================================================================================================================
|
||||
void RcSeq_Init(void)
|
||||
{
|
||||
SeqNb=0;
|
||||
ServoNb=0;
|
||||
SeqNb = 0;
|
||||
ServoNb = 0;
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
for(uint8_t ChIdx=0;ChIdx<RC_CMD_MAX_NB;ChIdx++)
|
||||
for(uint8_t ChIdx = 0; ChIdx < RC_CMD_MAX_NB; ChIdx++)
|
||||
{
|
||||
RcChannel[ChIdx].Pos.Idx=NO_POS;
|
||||
RcChannel[ChIdx].Pos.Idx = NO_POS;
|
||||
}
|
||||
#endif
|
||||
#ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
for(uint8_t SeqIdx=0;SeqIdx<SEQUENCE_MAX_NB;SeqIdx++)
|
||||
for(uint8_t SeqIdx = 0; SeqIdx < SEQUENCE_MAX_NB; SeqIdx++)
|
||||
{
|
||||
CmdSequence[SeqIdx].InProgress=0;
|
||||
CmdSequence[SeqIdx].TableOrShortAction=NULL;
|
||||
CmdSequence[SeqIdx].SequenceLength=0;
|
||||
CmdSequence[SeqIdx].ShortActionMap=0;
|
||||
CmdSequence[SeqIdx].InProgress = 0;
|
||||
CmdSequence[SeqIdx].TableOrShortAction = NULL;
|
||||
CmdSequence[SeqIdx].SequenceLength = 0;
|
||||
CmdSequence[SeqIdx].ShortActionMap = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
@ -242,36 +244,53 @@ char *RcSeq_LibTextVersionRevision(void)
|
||||
void RcSeq_DeclareServo(uint8_t Idx, uint8_t DigitalPin)
|
||||
{
|
||||
#ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
if(Idx<SERVO_MAX_NB)
|
||||
if(Idx < SERVO_MAX_NB)
|
||||
{
|
||||
Servo[Idx].Motor.attach(DigitalPin);
|
||||
Servo[Idx].SeqLineInProgress=NO_SEQ_LINE;
|
||||
if(ServoNb<(Idx+1)) ServoNb=(Idx+1);
|
||||
Servo[Idx].SeqLineInProgress = NO_SEQ_LINE;
|
||||
if(ServoNb < (Idx + 1)) ServoNb = (Idx + 1);
|
||||
}
|
||||
#else
|
||||
if(Idx<SERVO_MAX_NB)
|
||||
if(Idx < SERVO_MAX_NB)
|
||||
{
|
||||
ServoNb++;
|
||||
if(!Servo) Servo=(ServoSt_t**)malloc(sizeof(ServoSt_t));
|
||||
else Servo=(ServoSt_t**)realloc(Servo, sizeof(ServoSt_t)*ServoNb);
|
||||
Servo[Idx] AsMember Motor.attach(DigitalPin);
|
||||
Servo[Idx] AsMember SeqLineInProgress=NO_SEQ_LINE;
|
||||
if(!Servo) Servo = (ServoSt_t*)malloc(sizeof(ServoSt_t));
|
||||
else Servo = (ServoSt_t*)realloc(Servo, sizeof(ServoSt_t) * ServoNb);
|
||||
Servo[Idx].Motor.attach(DigitalPin);
|
||||
Servo[Idx].SeqLineInProgress = NO_SEQ_LINE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
//========================================================================================================================
|
||||
void RcSeq_ServoWrite(uint8_t Idx, uint16_t Angle)
|
||||
{
|
||||
if(Idx < SERVO_MAX_NB)
|
||||
{
|
||||
Servo[Idx].Motor.write(Angle);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//========================================================================================================================
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
void RcSeq_DeclareSignal(uint8_t Idx, uint8_t DigitalPin)
|
||||
{
|
||||
if(Idx<RC_CMD_MAX_NB)
|
||||
if(Idx < RC_CMD_MAX_NB)
|
||||
{
|
||||
RcChannel[Idx].Pulse.attach(DigitalPin);
|
||||
CmdSignalNb++;
|
||||
}
|
||||
}
|
||||
//========================================================================================================================
|
||||
void RcSeq_DeclareKeyboardOrStickOrCustom(uint8_t ChIdx, uint8_t Type, uint16_t PulseMinUs, uint16_t PulseMaxUs, KeyMap_t *KeyMap, uint8_t PosNb)
|
||||
boolean RcSeq_SignalTimeout(uint8_t Idx, uint8_t TimeoutMs, uint8_t *State)
|
||||
{
|
||||
if(Idx < RC_CMD_MAX_NB)
|
||||
{
|
||||
return(RcChannel[Idx].Pulse.timeout(TimeoutMs, State));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
//========================================================================================================================
|
||||
void RcSeq_DeclareKeyboardOrStickOrCustom(uint8_t ChIdx, uint8_t Type, uint16_t PulseMinUs, uint16_t PulseMaxUs, const KeyMap_t *KeyMap, uint8_t PosNb)
|
||||
{
|
||||
RcChannel[ChIdx].Type = Type;
|
||||
RcChannel[ChIdx].PosNb = PosNb;
|
||||
@ -281,50 +300,62 @@ void RcSeq_DeclareKeyboardOrStickOrCustom(uint8_t ChIdx, uint8_t Type, uint16_t
|
||||
RcChannel[ChIdx].KeyMap = KeyMap;
|
||||
}
|
||||
//========================================================================================================================
|
||||
void RcSeq_DeclareCustomKeyboard(uint8_t ChIdx, KeyMap_t *KeyMapTbl, uint8_t KeyNb)
|
||||
void RcSeq_DeclareCustomKeyboard(uint8_t ChIdx, const KeyMap_t *KeyMapTbl, uint8_t KeyNb)
|
||||
{
|
||||
RcSeq_DeclareKeyboardOrStickOrCustom(ChIdx, RC_CMD_CUSTOM, 0, 0, KeyMapTbl, KeyNb);
|
||||
}
|
||||
#endif
|
||||
//========================================================================================================================
|
||||
void RcSeq_DeclareCommandAndSequence(uint8_t CmdIdx,uint8_t Pos,SequenceSt_t *Table, uint8_t SequenceLength)
|
||||
#ifdef RC_SEQ_CONTROL_SUPPORT
|
||||
void RcSeq_DeclareCommandAndSequence(uint8_t CmdIdx,uint8_t Pos, const SequenceSt_t *Table, uint8_t SequenceLength, uint8_t(*Control)(uint8_t Action, uint8_t SeqIdx))
|
||||
#else
|
||||
void RcSeq_DeclareCommandAndSequence(uint8_t CmdIdx,uint8_t Pos, const SequenceSt_t *Table, uint8_t SequenceLength)
|
||||
#endif
|
||||
{
|
||||
uint8_t Idx, ServoIdx;
|
||||
uint16_t StartInDegrees;
|
||||
uint32_t StartMinMs[SERVO_MAX_NB];
|
||||
#ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
for(Idx=0;Idx<SEQUENCE_MAX_NB;Idx++)
|
||||
#ifndef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
if(!CmdSequence) CmdSequence = (CmdSequenceSt_t*)malloc(sizeof(CmdSequenceSt_t));
|
||||
else CmdSequence = (CmdSequenceSt_t*)realloc(CmdSequence, sizeof(CmdSequenceSt_t) * (SeqNb + 1));
|
||||
Idx = SeqNb;
|
||||
SeqNb++;
|
||||
#else
|
||||
for(Idx = 0; Idx < SEQUENCE_MAX_NB; Idx++)
|
||||
{
|
||||
if(!CmdSequence[Idx].TableOrShortAction)
|
||||
{
|
||||
CmdSequence[Idx].CmdIdx=CmdIdx;
|
||||
CmdSequence[Idx].Pos=Pos;
|
||||
CmdSequence[Idx].TableOrShortAction=(void*)Table;
|
||||
CmdSequence[Idx].SequenceLength=SequenceLength;
|
||||
#endif
|
||||
CmdSequence[Idx].CmdIdx = CmdIdx;
|
||||
CmdSequence[Idx].Pos = Pos;
|
||||
CmdSequence[Idx].TableOrShortAction = (void*)Table;
|
||||
CmdSequence[Idx].SequenceLength = SequenceLength;
|
||||
#ifdef RC_SEQ_CONTROL_SUPPORT
|
||||
CmdSequence[Idx].Control = Control;
|
||||
#endif
|
||||
#ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
SeqNb++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
LoadSequenceOrShortAction(CmdIdx,Pos,(void*)Table, SequenceLength);
|
||||
#endif
|
||||
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
|
||||
/* Get initial pulse width for each Servo */
|
||||
for(Idx=0;Idx<SERVO_MAX_NB;Idx++)
|
||||
for(Idx = 0; Idx < SERVO_MAX_NB; Idx++)
|
||||
{
|
||||
StartMinMs[Idx]=0xFFFFFFFF;
|
||||
StartMinMs[Idx] = 0xFFFFFFFF;
|
||||
}
|
||||
for(Idx=0;Idx<SequenceLength;Idx++)
|
||||
for(Idx = 0; Idx < SequenceLength; Idx++)
|
||||
{
|
||||
ServoIdx=(int8_t)PGM_READ_8(Table[Idx].ServoIndex);
|
||||
if(ServoIdx!=255)
|
||||
ServoIdx = (int8_t)PGM_READ_8(Table[Idx].ServoIndex);
|
||||
if(ServoIdx != 255)
|
||||
{
|
||||
if((uint32_t)PGM_READ_32(Table[Idx].StartMotionOffsetMs)<=StartMinMs[ServoIdx])
|
||||
if((uint32_t)PGM_READ_32(Table[Idx].StartMotionOffsetMs) <= StartMinMs[ServoIdx])
|
||||
{
|
||||
StartMinMs[ServoIdx]=(uint32_t)PGM_READ_32(Table[Idx].StartMotionOffsetMs);
|
||||
StartInDegrees=(uint16_t)PGM_READ_8(Table[Idx].StartInDegrees);
|
||||
Servo[ServoIdx] AsMember Motor.write(StartInDegrees);
|
||||
StartMinMs[ServoIdx] = (uint32_t)PGM_READ_32(Table[Idx].StartMotionOffsetMs);
|
||||
StartInDegrees = (uint16_t)PGM_READ_8(Table[Idx].StartInDegrees);
|
||||
Servo[ServoIdx].Motor.write(StartInDegrees);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -332,49 +363,42 @@ uint32_t StartMinMs[SERVO_MAX_NB];
|
||||
}
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
//========================================================================================================================
|
||||
void RcSeq_DeclareCommandAndShortAction(uint8_t CmdIdx,uint8_t Pos,void(*ShortAction)(void))
|
||||
void RcSeq_DeclareCommandAndShortAction(uint8_t CmdIdx, uint8_t Pos, void(*ShortAction)(void))
|
||||
{
|
||||
#ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
uint8_t Idx;
|
||||
for(Idx=0;Idx<SEQUENCE_MAX_NB;Idx++)
|
||||
#ifndef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
if(!CmdSequence) CmdSequence = (CmdSequenceSt_t*)malloc(sizeof(CmdSequenceSt_t));
|
||||
else CmdSequence = (CmdSequenceSt_t*)realloc(CmdSequence, sizeof(CmdSequenceSt_t) * (SeqNb + 1));
|
||||
Idx = SeqNb;
|
||||
SeqNb++;
|
||||
#else
|
||||
for(Idx = 0; Idx < SEQUENCE_MAX_NB; Idx++)
|
||||
{
|
||||
if(!CmdSequence[Idx].TableOrShortAction)
|
||||
{
|
||||
CmdSequence[Idx].CmdIdx=CmdIdx;
|
||||
CmdSequence[Idx].Pos=Pos;
|
||||
CmdSequence[Idx].TableOrShortAction=(void*)ShortAction;
|
||||
#endif
|
||||
CmdSequence[Idx].CmdIdx = CmdIdx;
|
||||
CmdSequence[Idx].Pos = Pos;
|
||||
CmdSequence[Idx].TableOrShortAction = (void*)ShortAction;
|
||||
CmdSequence[Idx].SequenceLength = 0;
|
||||
#ifdef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
SeqNb++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
LoadSequenceOrShortAction(CmdIdx,Pos,(void*)ShortAction, 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT
|
||||
static void LoadSequenceOrShortAction(uint8_t CmdIdx,uint8_t Pos,void *SequenceOrShortAction, uint8_t SequenceLength)
|
||||
{
|
||||
if(!CmdSequence) CmdSequence=(CmdSequenceSt_t**)malloc(sizeof(CmdSequenceSt_t));
|
||||
else CmdSequence=(CmdSequenceSt_t**)realloc(CmdSequence,sizeof(CmdSequence)+sizeof(CmdSequenceSt_t));
|
||||
CmdSequence[SeqNb] AsMember CmdIdx=CmdIdx;
|
||||
CmdSequence[SeqNb] AsMember Pos=Pos;
|
||||
CmdSequence[SeqNb] AsMember TableOrShortAction=(void*)SequenceOrShortAction;
|
||||
CmdSequence[SeqNb] AsMember SequenceLength=SequenceLength;
|
||||
SeqNb++;
|
||||
}
|
||||
#endif
|
||||
//========================================================================================================================
|
||||
uint8_t RcSeq_LaunchSequence(SequenceSt_t *Table)
|
||||
uint8_t RcSeq_LaunchSequence(const SequenceSt_t *Table)
|
||||
{
|
||||
uint8_t Idx, Ret=0;
|
||||
for(Idx=0;Idx<SEQUENCE_MAX_NB;Idx++)
|
||||
uint8_t Idx, Ret = 0;
|
||||
for(Idx = 0; Idx < SEQUENCE_MAX_NB; Idx++)
|
||||
{
|
||||
if(CmdSequence[Idx] AsMember TableOrShortAction==(void*)Table)
|
||||
if(CmdSequence[Idx].TableOrShortAction == (void*)Table)
|
||||
{
|
||||
ExecuteSequence(CmdSequence[Idx] AsMember CmdIdx,CmdSequence[Idx] AsMember Pos);
|
||||
Ret=1;
|
||||
Ret = ExecuteSequence(CmdSequence[Idx].CmdIdx, CmdSequence[Idx].Pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -383,8 +407,8 @@ uint8_t Idx, Ret=0;
|
||||
//========================================================================================================================
|
||||
void RcSeq_Refresh(void)
|
||||
{
|
||||
static uint32_t NowMs=millis();
|
||||
static uint32_t StartChronoInterPulseMs=millis();
|
||||
static uint32_t NowMs = millis();
|
||||
static uint32_t StartChronoInterPulseMs = millis();
|
||||
SequenceSt_t *SequenceTable;
|
||||
void (*ShortAction)(void);
|
||||
int8_t ShortActionCnt;
|
||||
@ -398,100 +422,104 @@ int8_t CmdPos; /* Shall be signed */
|
||||
uint32_t RcPulseWidthUs;
|
||||
|
||||
/* Asynchronous RC Command acquisition */
|
||||
for(ChIdx=0;ChIdx<CmdSignalNb;ChIdx++)
|
||||
for(ChIdx = 0; ChIdx < CmdSignalNb; ChIdx++)
|
||||
{
|
||||
if(!RcChannel[ChIdx].Pulse.available()) continue; /* Channel not used or no pulse received */
|
||||
RcPulseWidthUs=RcChannel[ChIdx].Pulse.width_us();
|
||||
CmdPos=GetPos(ChIdx,RcPulseWidthUs);
|
||||
if(CmdPos>=0)
|
||||
RcPulseWidthUs = RcChannel[ChIdx].Pulse.width_us();
|
||||
CmdPos = GetPos(ChIdx, RcPulseWidthUs);
|
||||
// Serial.print("W=");Serial.print(RcPulseWidthUs);Serial.print(" P=");Serial.println((int)CmdPos);
|
||||
if(CmdPos >= 0)
|
||||
{
|
||||
if(RcChannel[ChIdx].Pos.Idx!=CmdPos)
|
||||
if(RcChannel[ChIdx].Pos.Idx != CmdPos)
|
||||
{
|
||||
RcChannel[ChIdx].Pos.Idx=CmdPos;
|
||||
RcChannel[ChIdx].Pos.StartChronoMs=millis();
|
||||
RcChannel[ChIdx].Pos.Idx = CmdPos;
|
||||
RcChannel[ChIdx].Pos.StartChronoMs = millis();
|
||||
}
|
||||
else
|
||||
{
|
||||
if((millis()-RcChannel[ChIdx].Pos.StartChronoMs)>=((RcChannel[ChIdx].Type==RC_CMD_STICK)?STICK_PULSE_CHECK_MS:KBD_PULSE_CHECK_MS)) /* Check the Pulse is valid at least for 100 ms or 50 ms */
|
||||
if((millis() - RcChannel[ChIdx].Pos.StartChronoMs) >= ((RcChannel[ChIdx].Type == RC_CMD_STICK)?STICK_PULSE_CHECK_MS:KBD_PULSE_CHECK_MS)) /* Check the Pulse is valid at least for 100 ms or 50 ms */
|
||||
{
|
||||
ExecuteSequence(ChIdx,CmdPos);
|
||||
RcChannel[ChIdx].Pos.Idx=NO_POS;
|
||||
ExecuteSequence(ChIdx, CmdPos);
|
||||
RcChannel[ChIdx].Pos.Idx = NO_POS;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RcChannel[ChIdx].Pos.Idx=NO_POS;
|
||||
RcChannel[ChIdx].Pos.Idx = NO_POS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
NowMs=millis();
|
||||
NowMs = millis();
|
||||
if((NowMs - StartChronoInterPulseMs) >= 20UL)
|
||||
{
|
||||
/* We arrive here every 20 ms */
|
||||
/* Asynchronous Servo Sequence management */
|
||||
for(int8_t Idx=0;Idx<SeqNb;Idx++)
|
||||
for(int8_t Idx = 0; Idx < SeqNb; Idx++)
|
||||
{
|
||||
if(!CmdSequence[Idx] AsMember InProgress || !CmdSequence[Idx] AsMember SequenceLength) continue;
|
||||
ShortActionCnt=-1;
|
||||
for(int8_t SeqLine=0;SeqLine<CmdSequence[Idx] AsMember SequenceLength;SeqLine++) /* Read all lines of the sequence table: this allows to run several servos simultaneously (not forcibly one after the other) */
|
||||
if(!CmdSequence[Idx].InProgress || !CmdSequence[Idx].SequenceLength) continue;
|
||||
ShortActionCnt = -1;
|
||||
for(int8_t SeqLine = 0; SeqLine < CmdSequence[Idx].SequenceLength; SeqLine++) /* Read all lines of the sequence table: this allows to run several servos simultaneously (not forcibly one after the other) */
|
||||
{
|
||||
SequenceTable=(SequenceSt_t *)CmdSequence[Idx] AsMember TableOrShortAction;
|
||||
ServoIdx=(int8_t)PGM_READ_8(SequenceTable[SeqLine].ServoIndex);
|
||||
SequenceTable = (SequenceSt_t *)CmdSequence[Idx].TableOrShortAction;
|
||||
ServoIdx = (int8_t)PGM_READ_8(SequenceTable[SeqLine].ServoIndex);
|
||||
#ifdef RC_SEQ_WITH_SHORT_ACTION_SUPPORT
|
||||
if(ServoIdx==255) /* Not a Servo: it's a short Action to perform only if not already done */
|
||||
if(ServoIdx == 255) /* Not a Servo: it's a short Action to perform only if not already done */
|
||||
{
|
||||
ShortActionCnt++;
|
||||
StartOfSeqMs = CmdSequence[Idx] AsMember StartChronoMs + (int32_t)PGM_READ_32(SequenceTable[SeqLine].StartMotionOffsetMs);
|
||||
if( (NowMs>=StartOfSeqMs) && !TST_BIT(CmdSequence[Idx] AsMember ShortActionMap,ShortActionCnt) )
|
||||
StartOfSeqMs = CmdSequence[Idx].StartChronoMs + (int32_t)PGM_READ_32(SequenceTable[SeqLine].StartMotionOffsetMs);
|
||||
if( (NowMs >= StartOfSeqMs) && !TST_BIT(CmdSequence[Idx].ShortActionMap, ShortActionCnt) )
|
||||
{
|
||||
ShortAction=(void(*)(void))PGM_READ_16(SequenceTable[SeqLine].ShortAction);
|
||||
ShortAction = (void(*)(void))PGM_READ_16(SequenceTable[SeqLine].ShortAction);
|
||||
ShortAction();
|
||||
SET_BIT(CmdSequence[Idx] AsMember ShortActionMap,ShortActionCnt); /* Mark short Action as performed */
|
||||
/* If the last line contains an Action AsMember End of Sequence */
|
||||
if(SeqLine==(CmdSequence[Idx] AsMember SequenceLength-1))
|
||||
SET_BIT(CmdSequence[Idx].ShortActionMap, ShortActionCnt); /* Mark short Action as performed */
|
||||
/* If the last line contains an Action: End of Sequence */
|
||||
if(SeqLine == (CmdSequence[Idx].SequenceLength - 1))
|
||||
{
|
||||
CmdSequence[Idx] AsMember InProgress=0;
|
||||
CmdSequence[Idx] AsMember ShortActionMap=0; /* Mark all Short Action as not performed */
|
||||
CmdSequence[Idx].InProgress = 0;
|
||||
CmdSequence[Idx].ShortActionMap = 0; /* Mark all Short Action as not performed */
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
|
||||
if(Servo[ServoIdx] AsMember RefreshNb && SeqLine!=Servo[ServoIdx] AsMember SeqLineInProgress)
|
||||
if(Servo[ServoIdx].RefreshNb && SeqLine != Servo[ServoIdx].SeqLineInProgress)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
StartOfSeqMs = CmdSequence[Idx] AsMember StartChronoMs + (int32_t)PGM_READ_32(SequenceTable[SeqLine].StartMotionOffsetMs);
|
||||
StartOfSeqMs = CmdSequence[Idx].StartChronoMs + (int32_t)PGM_READ_32(SequenceTable[SeqLine].StartMotionOffsetMs);
|
||||
MotionDurationMs = (int32_t)PGM_READ_32(SequenceTable[SeqLine].MotionDurationMs);
|
||||
EndOfSeqMs = StartOfSeqMs + MotionDurationMs;
|
||||
if(!Servo[ServoIdx] AsMember RefreshNb && Servo[ServoIdx] AsMember SeqLineInProgress==NO_SEQ_LINE)
|
||||
if(!Servo[ServoIdx].RefreshNb && Servo[ServoIdx].SeqLineInProgress == NO_SEQ_LINE)
|
||||
{
|
||||
if( (NowMs>=StartOfSeqMs) && (NowMs<=EndOfSeqMs) )
|
||||
if( (NowMs >= StartOfSeqMs) && (NowMs <= EndOfSeqMs) )
|
||||
{
|
||||
Servo[ServoIdx] AsMember SeqLineInProgress=SeqLine;
|
||||
StartInDegrees=(uint16_t)PGM_READ_8(SequenceTable[SeqLine].StartInDegrees);
|
||||
Servo[ServoIdx] AsMember RefreshNb=REFRESH_NB(MotionDurationMs);
|
||||
Servo[ServoIdx] AsMember Motor.write(StartInDegrees);
|
||||
Servo[ServoIdx].SeqLineInProgress = SeqLine;
|
||||
StartInDegrees = (uint16_t)PGM_READ_8(SequenceTable[SeqLine].StartInDegrees);
|
||||
Servo[ServoIdx].RefreshNb = REFRESH_NB(MotionDurationMs);
|
||||
Servo[ServoIdx].Motor.write(StartInDegrees);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A sequence line is in progress: update the next position */
|
||||
if(Servo[ServoIdx] AsMember RefreshNb) Servo[ServoIdx] AsMember RefreshNb--;
|
||||
StartInDegrees=(uint16_t)PGM_READ_8(SequenceTable[SeqLine].StartInDegrees);
|
||||
EndInDegrees=(uint16_t)PGM_READ_8(SequenceTable[SeqLine].EndInDegrees);
|
||||
Pos=(int32_t)EndInDegrees-((int32_t)Servo[ServoIdx] AsMember RefreshNb*STEP_IN_DEGREES_PER_REFRESH((int32_t)StartInDegrees,(int32_t)EndInDegrees,(int32_t)MotionDurationMs)); //For refresh max nb, Pos = StartInDegrees
|
||||
Servo[ServoIdx] AsMember Motor.write(Pos);
|
||||
if( !Servo[ServoIdx] AsMember RefreshNb )
|
||||
if(Servo[ServoIdx].RefreshNb) Servo[ServoIdx].RefreshNb--;
|
||||
StartInDegrees = (uint16_t)PGM_READ_8(SequenceTable[SeqLine].StartInDegrees);
|
||||
EndInDegrees = (uint16_t)PGM_READ_8(SequenceTable[SeqLine].EndInDegrees);
|
||||
Pos = (int32_t)EndInDegrees - ((int32_t)Servo[ServoIdx].RefreshNb * STEP_IN_DEGREES_PER_REFRESH((int32_t)StartInDegrees,(int32_t)EndInDegrees,(int32_t)MotionDurationMs)); //For refresh max nb, Pos = StartInDegrees
|
||||
Servo[ServoIdx].Motor.write(Pos);
|
||||
if( !Servo[ServoIdx].RefreshNb )
|
||||
{
|
||||
Servo[ServoIdx] AsMember SeqLineInProgress=NO_SEQ_LINE;
|
||||
Servo[ServoIdx].SeqLineInProgress = NO_SEQ_LINE;
|
||||
/* Last servo motion and refresh = 0 -> End of Sequence */
|
||||
if(SeqLine==(CmdSequence[Idx] AsMember SequenceLength-1))
|
||||
if(SeqLine == (CmdSequence[Idx].SequenceLength - 1))
|
||||
{
|
||||
CmdSequence[Idx] AsMember InProgress=0;
|
||||
CmdSequence[Idx] AsMember ShortActionMap=0; /* Mark all Short Action as not performed */
|
||||
CmdSequence[Idx].InProgress = 0;
|
||||
CmdSequence[Idx].ShortActionMap = 0; /* Mark all Short Action as not performed */
|
||||
#ifdef RC_SEQ_CONTROL_SUPPORT
|
||||
if(CmdSequence[Idx].Control != NULL) CmdSequence[Idx].Control(RC_SEQ_END_OF_SEQ, Idx);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -501,76 +529,94 @@ uint32_t RcPulseWidthUs;
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
|
||||
SoftRcPulseOut::refresh(1); /* Force Refresh */
|
||||
#endif
|
||||
StartChronoInterPulseMs=millis();
|
||||
StartChronoInterPulseMs = millis();
|
||||
}
|
||||
}
|
||||
|
||||
//========================================================================================================================
|
||||
// PRIVATE FUNCTIONS
|
||||
//========================================================================================================================
|
||||
static void ExecuteSequence(uint8_t CmdIdx, uint8_t Pos)
|
||||
static uint8_t ExecuteSequence(uint8_t CmdIdx, uint8_t Pos)
|
||||
{
|
||||
void(*ShortAction)(void);
|
||||
uint8_t Idx;
|
||||
uint8_t Idx, Ret = 0;
|
||||
|
||||
for(Idx=0;Idx<SeqNb;Idx++)
|
||||
for(Idx = 0; Idx < SeqNb; Idx++)
|
||||
{
|
||||
if((CmdSequence[Idx] AsMember CmdIdx==CmdIdx) && (CmdSequence[Idx] AsMember Pos==Pos))
|
||||
if((CmdSequence[Idx].CmdIdx == CmdIdx) && (CmdSequence[Idx].Pos == Pos))
|
||||
{
|
||||
#ifdef RC_SEQ_WITH_SHORT_ACTION_SUPPORT
|
||||
if(CmdSequence[Idx] AsMember TableOrShortAction && !CmdSequence[Idx] AsMember SequenceLength)
|
||||
if(CmdSequence[Idx].TableOrShortAction && !CmdSequence[Idx].SequenceLength)
|
||||
{
|
||||
/* It's a short action */
|
||||
ShortAction=(void(*)(void))CmdSequence[Idx] AsMember TableOrShortAction;
|
||||
ShortAction = (void(*)(void))CmdSequence[Idx].TableOrShortAction;
|
||||
ShortAction();
|
||||
Ret = 1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* It's a Table of Sequence */
|
||||
if(!CmdSequence[Idx] AsMember InProgress)
|
||||
if(!CmdSequence[Idx].InProgress)
|
||||
{
|
||||
CmdSequence[Idx] AsMember InProgress=1;
|
||||
CmdSequence[Idx] AsMember StartChronoMs=millis();
|
||||
#ifdef RC_SEQ_CONTROL_SUPPORT
|
||||
uint8_t Go = 1;
|
||||
if(CmdSequence[Idx].Control != NULL)
|
||||
{
|
||||
Go = CmdSequence[Idx].Control(RC_SEQ_START_CONDITION, Idx);
|
||||
// Serial.print(F("Go for Seq["));Serial.print(Idx);Serial.print(F("] "));Serial.println(Go?F("Yes"):F("No"));
|
||||
}
|
||||
if(Go)
|
||||
{
|
||||
CmdSequence[Idx].InProgress = 1;
|
||||
CmdSequence[Idx].StartChronoMs = millis();
|
||||
Ret = 1;
|
||||
}
|
||||
#else
|
||||
CmdSequence[Idx].InProgress = 1;
|
||||
CmdSequence[Idx].StartChronoMs = millis();
|
||||
Ret = 1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(Ret);
|
||||
}
|
||||
//========================================================================================================================
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
static int8_t GetPos(uint8_t ChIdx,uint16_t PulseWidthUs)
|
||||
static int8_t GetPos(uint8_t ChIdx, uint16_t PulseWidthUs)
|
||||
{
|
||||
int8_t Idx, Ret=-1;
|
||||
uint16_t PulseMinUs,PulseMaxUs;
|
||||
int8_t Idx, Ret = -1;
|
||||
uint16_t PulseMinUs, PulseMaxUs;
|
||||
|
||||
for(Idx=0;Idx<RcChannel[ChIdx].PosNb;Idx++)
|
||||
for(Idx = 0; Idx < RcChannel[ChIdx].PosNb; Idx++)
|
||||
{
|
||||
switch(RcChannel[ChIdx].Type)
|
||||
{
|
||||
case RC_CMD_STICK: /* No break: normal */
|
||||
case RC_CMD_MULTI_POS_SW:
|
||||
if( (RcChannel[ChIdx].Type==RC_CMD_MULTI_POS_SW) || ((RcChannel[ChIdx].Type==RC_CMD_STICK) && (Idx<(RcChannel[ChIdx].PosNb/2))) )
|
||||
if( (RcChannel[ChIdx].Type == RC_CMD_MULTI_POS_SW) || ((RcChannel[ChIdx].Type == RC_CMD_STICK) && (Idx < (RcChannel[ChIdx].PosNb / 2))) )
|
||||
{
|
||||
PulseMinUs=RcChannel[ChIdx].PulseMinUs+KEY_MIN_VAL(Idx,RcChannel[ChIdx].StepUs);
|
||||
PulseMaxUs=RcChannel[ChIdx].PulseMinUs+KEY_MAX_VAL(Idx,RcChannel[ChIdx].StepUs);
|
||||
PulseMinUs = RcChannel[ChIdx].PulseMinUs + KEY_MIN_VAL(Idx,RcChannel[ChIdx].StepUs);
|
||||
PulseMaxUs = RcChannel[ChIdx].PulseMinUs + KEY_MAX_VAL(Idx,RcChannel[ChIdx].StepUs);
|
||||
}
|
||||
else
|
||||
{
|
||||
PulseMinUs=RcChannel[ChIdx].PulseMaxUs-KEY_MAX_VAL(RcChannel[ChIdx].PosNb-1-Idx,RcChannel[ChIdx].StepUs);
|
||||
PulseMaxUs=RcChannel[ChIdx].PulseMaxUs-KEY_MIN_VAL(RcChannel[ChIdx].PosNb-1-Idx,RcChannel[ChIdx].StepUs);
|
||||
PulseMinUs = RcChannel[ChIdx].PulseMaxUs - KEY_MAX_VAL(RcChannel[ChIdx].PosNb - 1 - Idx, RcChannel[ChIdx].StepUs);
|
||||
PulseMaxUs = RcChannel[ChIdx].PulseMaxUs - KEY_MIN_VAL(RcChannel[ChIdx].PosNb - 1 - Idx, RcChannel[ChIdx].StepUs);
|
||||
}
|
||||
break;
|
||||
|
||||
case RC_CMD_CUSTOM:
|
||||
PulseMinUs=(uint16_t)PGM_READ_16(RcChannel[ChIdx].KeyMap[Idx].Min);
|
||||
PulseMaxUs=(uint16_t)PGM_READ_16(RcChannel[ChIdx].KeyMap[Idx].Max);
|
||||
PulseMinUs = (uint16_t)PGM_READ_16(RcChannel[ChIdx].KeyMap[Idx].Min);
|
||||
PulseMaxUs = (uint16_t)PGM_READ_16(RcChannel[ChIdx].KeyMap[Idx].Max);
|
||||
break;
|
||||
}
|
||||
if((PulseWidthUs>=PulseMinUs) && (PulseWidthUs<=PulseMaxUs))
|
||||
if((PulseWidthUs >= PulseMinUs) && (PulseWidthUs <= PulseMaxUs))
|
||||
{
|
||||
Ret=Idx;
|
||||
Ret = Idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define RC_SEQ_H
|
||||
|
||||
/*
|
||||
English: by RC Navy (2012/2013)
|
||||
English: by RC Navy (2012-2015)
|
||||
=======
|
||||
<RcSeq> is an asynchronous library for ATmega328P (UNO), ATtiny84 and ATtiny85 to easily create servo's sequences and/or to execute short actions from RC commands.
|
||||
It can also be used to trig some short "actions" (the duration must be less than 20ms to not disturb the servo commands)
|
||||
@ -23,7 +23,7 @@
|
||||
CAUTION: the end user shall also use asynchronous programmation method in the loop() function (no blocking functions such as delay() or pulseIn()).
|
||||
http://p.loussouarn.free.fr
|
||||
|
||||
Francais: par RC Navy (2012/2013)
|
||||
Francais: par RC Navy (2012-2015)
|
||||
========
|
||||
<RcSeq> est une librairie asynchrone pour ATmega328P (UNO), ATtiny84 et ATtiny85 pour creer facilement des sequences de servos et/ou executer des actions depuis des commandes RC.
|
||||
Elle peut egalement etre utilisee pour lancer des "actions courtes" (la duree doit etre inferieure a 20ms pour ne pas perturber la commande des servos)
|
||||
@ -48,19 +48,17 @@
|
||||
/* RCSEQ LIBRARY CONFIGURATION */
|
||||
/**********************************************/
|
||||
#define RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT /* Comment this line if you use <DigiUSB> library in your sketch */
|
||||
//#define RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT /* Uncomment this if you use <SoftRcPulseOut> library in your sketch for servos and ESC */
|
||||
#define RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT /* Uncomment this if you use <SoftRcPulseOut> library in your sketch for servos and ESC */
|
||||
#define RC_SEQ_WITH_SHORT_ACTION_SUPPORT /* Uncomment this to allows to put call to short action in sequence table */
|
||||
#define RC_SEQ_CONTROL_SUPPORT /* Uncomment this to allow control on sequences: start condition and end of sequence */
|
||||
|
||||
|
||||
|
||||
/**********************************************/
|
||||
/* /!\ Do not touch below /!\ */
|
||||
/**********************************************/
|
||||
/* For an easy Library Version Management */
|
||||
#define RC_SEQ_LIB_VERSION 2
|
||||
#define RC_SEQ_LIB_REVISION 0
|
||||
|
||||
#define RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT /* Do NOT comment this line for DigiSpark, but you can for UNO */
|
||||
#define RC_SEQ_WITH_STATIC_MEM_ALLOC_SUPPORT /* Do NOT comment this line for now: still buggy (to do: fix this) */
|
||||
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
#include <TinyPinChange.h>
|
||||
@ -86,14 +84,26 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
#define SERVO_MAX_NB 10
|
||||
#define SEQUENCE_MAX_NB 8
|
||||
#define RC_CMD_MAX_NB 4
|
||||
#if defined(RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT)
|
||||
#if defined(__AVR_ATtiny85__)
|
||||
#define SERVO_MAX_NB 3 /* 3 is the maximum for DigiSpark if DigiUSB is used in the skecth */
|
||||
#else
|
||||
#if (defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny167__))
|
||||
#define SERVO_MAX_NB 6
|
||||
#else
|
||||
#define SERVO_MAX_NB 10
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define SERVO_MAX_NB 3 /* 3 is the maximum for DigiSpark if DigiUSB is used in the skecth */
|
||||
#define SEQUENCE_MAX_NB 1 /* 1 is the maximum for DigiSpark if DigiUSB is used in the skecth */
|
||||
#define RC_CMD_MAX_NB 0
|
||||
#define SERVO_MAX_NB 0
|
||||
#endif
|
||||
|
||||
#if (defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny167__))
|
||||
#define SEQUENCE_MAX_NB 4 /* 2 is the maximum for DigiSpark if DigiUSB is used in the skecth */
|
||||
#define RC_CMD_MAX_NB 2
|
||||
#else
|
||||
#define SEQUENCE_MAX_NB 10
|
||||
#define RC_CMD_MAX_NB 4
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
@ -122,7 +132,7 @@ typedef struct {
|
||||
#define MOTION_WITHOUT_SOFT_START_AND_STOP(ServoIndex,StartInDegrees,EndInDegrees,StartMvtOffsetMs,MvtDurationMs) \
|
||||
{ServoIndex, StartInDegrees, EndInDegrees, StartMvtOffsetMs, MvtDurationMs, NULL},
|
||||
|
||||
/* Macro to declare a short action (to use in "Sequence[]" structure table) */
|
||||
/* Macro to declare a short action (to be used in "Sequence[]" structure table) */
|
||||
#define SHORT_ACTION_TO_PERFORM(ShortAction, StartActionOffsetMs) {255, 0, 0, (StartActionOffsetMs), 0L, (ShortAction)},
|
||||
|
||||
enum {RC_CMD_STICK=0, RC_CMD_MULTI_POS_SW, RC_CMD_CUSTOM};
|
||||
@ -138,20 +148,27 @@ uint8_t RcSeq_LibRevision(void);
|
||||
char *RcSeq_LibTextVersionRevision(void);
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_OUT_SUPPORT
|
||||
void RcSeq_DeclareServo(uint8_t Idx, uint8_t DigitalPin);
|
||||
void RcSeq_ServoWrite(uint8_t Idx, uint16_t Angle);
|
||||
#endif
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
void RcSeq_DeclareSignal(uint8_t Idx, uint8_t DigitalPin);
|
||||
void RcSeq_DeclareKeyboardOrStickOrCustom(uint8_t ChIdx, uint8_t Type, uint16_t PulseMinUs, uint16_t PulseMaxUs, KeyMap_t *KeyMapTbl, uint8_t PosNb);
|
||||
void RcSeq_DeclareCustomKeyboard(uint8_t ChIdx, KeyMap_t *KeyMapTbl, uint8_t PosNb);
|
||||
boolean RcSeq_SignalTimeout(uint8_t Idx, uint8_t TimeoutMs, uint8_t *State);
|
||||
void RcSeq_DeclareKeyboardOrStickOrCustom(uint8_t ChIdx, uint8_t Type, uint16_t PulseMinUs, uint16_t PulseMaxUs, const KeyMap_t *KeyMapTbl, uint8_t PosNb);
|
||||
void RcSeq_DeclareCustomKeyboard(uint8_t ChIdx, const KeyMap_t *KeyMapTbl, uint8_t PosNb);
|
||||
#define RcSeq_DeclareStick(ChIdx, PulseMinUs, PulseMaxUs, PosNb) RcSeq_DeclareKeyboardOrStickOrCustom(ChIdx, RC_CMD_STICK, PulseMinUs, PulseMaxUs, NULL, PosNb)
|
||||
#define RcSeq_DeclareMultiPosSwitch(ChIdx, PulseMinUs, PulseMaxUs, PosNb) RcSeq_DeclareKeyboardOrStickOrCustom(ChIdx, RC_CMD_MULTI_POS_SW, PulseMinUs, PulseMaxUs, NULL, PosNb)
|
||||
#define RcSeq_DeclareKeyboard(ChIdx, PulseMinUs, PulseMaxUs, KeyNb) RcSeq_DeclareKeyboardOrStickOrCustom(ChIdx, RC_CMD_MULTI_POS_SW, PulseMinUs, PulseMaxUs, NULL, KeyNb)
|
||||
#ifdef RC_SEQ_WITH_SHORT_ACTION_SUPPORT
|
||||
void RcSeq_DeclareCommandAndShortAction(uint8_t CmdIdx,uint8_t TypeCmd,void(*ShortAction)(void));
|
||||
void RcSeq_DeclareCommandAndShortAction(uint8_t CmdIdx, uint8_t TypeCmd, void(*ShortAction)(void));
|
||||
#endif
|
||||
#endif
|
||||
void RcSeq_DeclareCommandAndSequence(uint8_t CmdIdx,uint8_t TypeCmd,SequenceSt_t *Table, uint8_t SequenceLength);
|
||||
uint8_t RcSeq_LaunchSequence(SequenceSt_t *Table);
|
||||
#ifdef RC_SEQ_CONTROL_SUPPORT
|
||||
void RcSeq_DeclareCommandAndSequence(uint8_t CmdIdx, uint8_t TypeCmd, const SequenceSt_t *Table, uint8_t SequenceLength, uint8_t(*Control)(uint8_t Action, uint8_t CmdSeqIdx));
|
||||
enum {RC_SEQ_START_CONDITION, RC_SEQ_END_OF_SEQ};
|
||||
#else
|
||||
void RcSeq_DeclareCommandAndSequence(uint8_t CmdIdx, uint8_t TypeCmd, const SequenceSt_t *Table, uint8_t SequenceLength);
|
||||
#endif
|
||||
uint8_t RcSeq_LaunchSequence(const SequenceSt_t *Table);
|
||||
#ifdef RC_SEQ_WITH_SHORT_ACTION_SUPPORT
|
||||
#define RcSeq_LaunchShortAction(ShortAction) if(ShortAction) ShortAction()
|
||||
#endif
|
||||
@ -162,25 +179,28 @@ void RcSeq_Refresh(void);
|
||||
/*******************************************************/
|
||||
|
||||
/* Macro en Francais de declaration mouvement English native Macro to declare a motion */
|
||||
#define MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS MOTION_WITH_SOFT_START_AND_STOP
|
||||
#define MVT_SANS_DEBUT_ET_FIN_MVT_LENTS MOTION_WITHOUT_SOFT_START_AND_STOP
|
||||
#define ACTION_COURTE_A_EFFECTUER SHORT_ACTION_TO_PERFORM
|
||||
#define MVT_AVEC_DEBUT_ET_FIN_MVT_LENTS MOTION_WITH_SOFT_START_AND_STOP
|
||||
#define MVT_SANS_DEBUT_ET_FIN_MVT_LENTS MOTION_WITHOUT_SOFT_START_AND_STOP
|
||||
#define ACTION_COURTE_A_EFFECTUER SHORT_ACTION_TO_PERFORM
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
#define RC_CLAVIER_MAISON RC_CUSTOM_KEYBOARD
|
||||
#define VALEUR_CENTRALE_US CENTER_VALUE_US
|
||||
#define RC_CLAVIER_MAISON RC_CUSTOM_KEYBOARD
|
||||
#define VALEUR_CENTRALE_US CENTER_VALUE_US
|
||||
#endif
|
||||
#ifdef RC_SEQ_CONTROL_SUPPORT
|
||||
#define RC_SEQ_CONDITION_DE_DEPART RC_SEQ_START_CONDITION
|
||||
#define RC_SEQ_FIN_DE_SEQ RC_SEQ_END_OF_SEQ
|
||||
#endif
|
||||
|
||||
/* Methodes en Francais English native methods */
|
||||
#ifdef RC_SEQ_WITH_SOFT_RC_PULSE_IN_SUPPORT
|
||||
#define RcSeq_DeclareManche RcSeq_DeclareStick
|
||||
#define RcSeq_DeclareClavier RcSeq_DeclareKeyboard
|
||||
#define RcSeq_DeclareClavierMaison RcSeq_DeclareCustomKeyboard
|
||||
#define RcSeq_DeclareInterMultiPos RcSeq_DeclareMultiPosSwitch
|
||||
#define RcSeq_DeclareCommandeEtActionCourte RcSeq_DeclareCommandAndShortAction
|
||||
#define RcSeq_DeclareManche RcSeq_DeclareStick
|
||||
#define RcSeq_DeclareClavier RcSeq_DeclareKeyboard
|
||||
#define RcSeq_DeclareClavierMaison RcSeq_DeclareCustomKeyboard
|
||||
#define RcSeq_DeclareInterMultiPos RcSeq_DeclareMultiPosSwitch
|
||||
#define RcSeq_DeclareCommandeEtActionCourte RcSeq_DeclareCommandAndShortAction
|
||||
#endif
|
||||
#define RcSeq_DeclareCommandeEtSequence RcSeq_DeclareCommandAndSequence
|
||||
#define RcSeq_LanceSequence RcSeq_LaunchSequence
|
||||
#define RcSeq_LanceActionCourte RcSeq_LaunchShortAction
|
||||
#define RcSeq_Rafraichit RcSeq_Refresh
|
||||
#define RcSeq_DeclareCommandeEtSequence RcSeq_DeclareCommandAndSequence
|
||||
#define RcSeq_LanceSequence RcSeq_LaunchSequence
|
||||
#define RcSeq_LanceActionCourte RcSeq_LaunchShortAction
|
||||
#define RcSeq_Rafraichit RcSeq_Refresh
|
||||
|
||||
#endif
|
||||
|
116
hardware/digistump/avr/libraries/DigisparkRcSeq/Readme.md
Normal file
116
hardware/digistump/avr/libraries/DigisparkRcSeq/Readme.md
Normal file
@ -0,0 +1,116 @@
|
||||
RcSeq library
|
||||
=============
|
||||
|
||||
**RcSeq** is an asynchronous library for ATmega328P (**UNO**), ATmega2560 (**MEGA**), ATtiny84, ATtiny85 (**Digispark**) and ATtiny167 (**Digispark pro**) to easily create **servo's sequences** and/or to execute **short actions** from RC commands, from a digital input, or from a launch function called in the sketch.
|
||||
|
||||
The **A**pplication **P**rogramming **I**nterface (**API**) makes **RcSeq** library very easy to use.
|
||||
|
||||
Some definitions:
|
||||
----------------
|
||||
|
||||
* **Sequence**: is used to sequence one or several servos (sequence is defined in a structure in the user's sketch to be performed when the RC command rises). The Sequence table (structure) may contain some servo motions and some short actions to call at a predefined time. For each servo, start angle, end angle and speed are tunable.
|
||||
|
||||
* **Short Action**: is used to perform a quick action (action is a short function defined in the user's sketch to be called when the RC command rises). The duration must be less than 20ms to not disturb the servo commands.
|
||||
|
||||
Some examples of use cases:
|
||||
--------------------------
|
||||
* **A landing gear retract:**
|
||||
* Lock, door and leg servos sequenced with a single RC channel
|
||||
* from a predefined position of the stick on the transmitter
|
||||
* from the 2 positions "Aux Channel" of the transmitter
|
||||
|
||||
* **Navigation lights for aircraft:**
|
||||
* Anticollision, beacon, landing lights commanded:
|
||||
* from predefined positions of the stick on the transmitter
|
||||
* from push-buttons in place of the stick potentiometer
|
||||
|
||||
|
||||
* **Multi-switch:**
|
||||
* Up to 8 digital pins driven from a single RC channel
|
||||
* using the stick of the transmitter
|
||||
* using 8 push-buttons in place of the stick potentiometer
|
||||
|
||||
* **Zodiac animation:**
|
||||
* A pneumatic Zodiac dropped at sea and lifted back to the deck of a ship. Drop and lift sequences commanded:
|
||||
* from predefined positions of the stick on the transmitter
|
||||
* from a regular ON/OFF switch (for demo on table without RC set)
|
||||
|
||||
* **Animatronics sequences:**
|
||||
|
||||
* leg motion,
|
||||
* mouth motion,
|
||||
* eyes motion,
|
||||
* etc.
|
||||
|
||||
Triggers:
|
||||
--------
|
||||
|
||||
**Sequences** and **short actions** can be trigged by:
|
||||
|
||||
* a RC signal (eg: RC receiver output)
|
||||
|
||||
* from one or several **predefined positions of a stick** of the transmitter
|
||||
|
||||
* from one or several **push-button** (keyboard) replacing a a stick of the transmitter. (**RcSeq** assumes Push-Buttons associated Pulse duration are equidistant).
|
||||
|
||||
* from **Custom Keyboard** replacing a stick of the the transmitter. (The pulse durations can be defined independently for each Push-Button).
|
||||
|
||||
* from **Multi position switch** (2 pos switch, 3 pos switch, or more, eg. rotactor) replacing a stick of the the transmitter.
|
||||
|
||||
* a regular ON/OFF switch (no RC set required).
|
||||
|
||||
* a launch function call in the sketch.
|
||||
|
||||
API/methods:
|
||||
-----------
|
||||
* RcSeq_Init()
|
||||
* RcSeq_DeclareSignal()
|
||||
* RcSeq_DeclareStick()
|
||||
* RcSeq_DeclareKeyboard()
|
||||
* RcSeq_DeclareCustomKeyboard()
|
||||
* RcSeq_DeclareMultiPosSwitch()
|
||||
* RcSeq_SignalTimeout()
|
||||
* RcSeq_DeclareServo()
|
||||
* RcSeq_DeclareCommandAndSequence()
|
||||
* RcSeq_DeclareCommandAndShortAction()
|
||||
* RcSeq_LaunchSequence()
|
||||
* RcSeq_LaunchShortAction()
|
||||
* RcSeq_Refresh()
|
||||
* RcSeq_LibVersion()
|
||||
* RcSeq_LibRevision()
|
||||
* RcSeq_LibTextVersionRevision()
|
||||
|
||||
Macros and constants:
|
||||
--------------------
|
||||
* const SequenceSt_t
|
||||
* const KeyMap_t
|
||||
* RC_SEQUENCE()
|
||||
* RC_CUSTOM_KEYBOARD()
|
||||
* SHORT_ACTION_TO_PERFORM()
|
||||
* MOTION_WITH_SOFT_START_AND_STOP()
|
||||
* MOTION_WITHOUT_SOFT_START_AND_STOP()
|
||||
* CENTER_VALUE_US
|
||||
* RC_SEQ_START_CONDITION
|
||||
* RC_SEQ_END_OF_SEQ
|
||||
|
||||
Design considerations:
|
||||
---------------------
|
||||
|
||||
The **RcSeq** library requires 3 other libraries written by the same author:
|
||||
|
||||
1. **TinyPinChange**: a library to catch asynchronously the input change using Pin Change Interruption capability of the AVR microcontroller.
|
||||
|
||||
2. **SoftRcPulseIn**: a library to catch asynchronously the input pulses using **TinyPinChange** library.
|
||||
|
||||
3. **SoftRcPulseOut**: a library mainly based on the **SoftwareServo** library, but with a better pulse generation to limit jitter and with some other enhancements.
|
||||
|
||||
CAUTION:
|
||||
-------
|
||||
The end user shall also use asynchronous programmation method in the loop() function (no blocking functions such as delay() or pulseIn()).
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
||||
|
||||
|
@ -15,11 +15,13 @@ RcSeq_LibRevision KEYWORD2
|
||||
RcSeq_LibTextVersionRevision KEYWORD2
|
||||
RcSeq_Init KEYWORD2
|
||||
RcSeq_DeclareSignal KEYWORD2
|
||||
RcSeq_SignalTimeout KEYWORD2
|
||||
RcSeq_DeclareKeyboard KEYWORD2
|
||||
RcSeq_DeclareClavier KEYWORD2
|
||||
RcSeq_DeclareStick KEYWORD2
|
||||
RcSeq_DeclareManche KEYWORD2
|
||||
RcSeq_DeclareServo KEYWORD2
|
||||
RcSeq_ServoWrite KEYWORD2
|
||||
RcSeq_DeclareCustomKeyboard KEYWORD2
|
||||
RcSeq_DeclareClavierMaison KEYWORD2
|
||||
RcSeq_DeclareMultiPosSwitch KEYWORD2
|
||||
@ -51,3 +53,8 @@ RC_CLAVIER_MAISON LITERAL1
|
||||
RC_SEQUENCE LITERAL1
|
||||
CENTER_VALUE_US LITERAL1
|
||||
VALEUR_CENTRALE_US LITERAL1
|
||||
RC_SEQ_START_CONDITION LITERAL1
|
||||
RC_SEQ_CONDITION_DE_DEPART LITERAL1
|
||||
RC_SEQ_END_OF_SEQ LITERAL1
|
||||
RC_SEQ_FIN_DE_SEQ LITERAL1
|
||||
|
||||
|
@ -0,0 +1,52 @@
|
||||
SoftRcPulseIn library
|
||||
======================
|
||||
|
||||
**SoftRcPulseIn** is an asynchronous library designed to read RC pulse signals. It is a non-blocking version of arduino **pulseIn()** function.
|
||||
|
||||
Some examples of use cases:
|
||||
-------------------------
|
||||
* **RC Servo/ESC/Brushless Controller**
|
||||
* **Multi-switch (RC Channel to digital outputs converter)** (look at **RcSeq** library)
|
||||
* **Servo sequencer** (look at **RcSeq** library which uses **SoftRcPulseOut** library)
|
||||
* **RC Robot using wheels with modified Servo to support 360° rotation**
|
||||
* **RC pulse stretcher** (in conjunction with **SoftRcPulseOut** library)
|
||||
|
||||
Supported Arduinos:
|
||||
------------------
|
||||
* **ATmega328 (UNO)**
|
||||
* **ATmega2560 (MEGA)**
|
||||
* **ATtiny84 (Standalone)**
|
||||
* **ATtiny85 (Standalone or Digispark)**
|
||||
* **ATtiny167 (Digispark pro)**
|
||||
|
||||
Tip and Tricks:
|
||||
--------------
|
||||
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
|
||||
|
||||
API/methods:
|
||||
-----------
|
||||
* attach()
|
||||
* available()
|
||||
* width_us()
|
||||
* timeout()
|
||||
* LibVersion()
|
||||
* LibRevision()
|
||||
* LibTextVersionRevision()
|
||||
|
||||
Design considerations:
|
||||
---------------------
|
||||
The **SoftRcPulseIn** library relies the **TinyPinChange** library. This one shall be included in the sketch as well.
|
||||
|
||||
On the arduino MEGA, as all the pins do not support "pin change interrupt", only the following pins are supported:
|
||||
|
||||
* 10 -> 15
|
||||
* 50 -> 53
|
||||
* A8 -> A15
|
||||
|
||||
On other devices (ATmega328, ATtiny84, ATtiny85 and ATtiny167), all the pins are usable.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
||||
|
@ -1,19 +1,22 @@
|
||||
/*
|
||||
English: by RC Navy (2012)
|
||||
English: by RC Navy (2012-2015)
|
||||
=======
|
||||
<SoftRcPulseIn>: an asynchronous library to read Input Pulse Width from standard Hobby Radio-Control. This library is a non-blocking version of pulseIn().
|
||||
http://p.loussouarn.free.fr
|
||||
|
||||
Francais: par RC Navy (2012)
|
||||
V1.0: initial release
|
||||
V1.1: asynchronous timeout support added (up to 250ms)
|
||||
Francais: par RC Navy (2012-2015)
|
||||
========
|
||||
<SoftRcPulseIn>: une librairie asynchrone pour lire les largeur d'impulsions des Radio-Commandes standards. Cette librairie est une version non bloquante de pulsIn().
|
||||
http://p.loussouarn.free.fr
|
||||
V1.0: release initiale
|
||||
V1.1: support de timeout asynchrone ajoutee (jusqu'a 250ms)
|
||||
*/
|
||||
|
||||
#include "SoftRcPulseIn.h"
|
||||
|
||||
#define LIB_VERSION 1
|
||||
#define LIB_REVISION 0
|
||||
#define LIB_VERSION 1
|
||||
#define LIB_REVISION 1
|
||||
|
||||
#define STR(s) #s
|
||||
#define MAKE_TEXT_VER_REV(Ver,Rev) STR(Ver)"."STR(Rev)
|
||||
@ -31,15 +34,15 @@ uint8_t SoftRcPulseIn::attach(uint8_t Pin, uint16_t PulseMin_us/*=600*/, uint16_
|
||||
uint8_t Ret=0;
|
||||
|
||||
_Pin=Pin;
|
||||
_PinMask=TinyPinChange_PinToMsk(Pin);
|
||||
_Min_us=PulseMin_us;
|
||||
_Max_us=PulseMax_us;
|
||||
_PinMask = TinyPinChange_PinToMsk(Pin);
|
||||
_Min_us = PulseMin_us;
|
||||
_Max_us = PulseMax_us;
|
||||
next = first;
|
||||
first = this;
|
||||
pinMode(_Pin,INPUT);
|
||||
digitalWrite(_Pin, HIGH);
|
||||
_VirtualPortIdx=TinyPinChange_RegisterIsr(_Pin,SoftRcPulseIn::SoftRcPulseInInterrupt);
|
||||
if(_VirtualPortIdx>=0)
|
||||
_VirtualPortIdx = TinyPinChange_RegisterIsr(_Pin, SoftRcPulseIn::SoftRcPulseInInterrupt);
|
||||
if(_VirtualPortIdx >= 0)
|
||||
{
|
||||
TinyPinChange_EnablePin(_Pin);
|
||||
Ret=1;
|
||||
@ -70,19 +73,32 @@ uint16_t PulseWidth_us;
|
||||
if(_Available)
|
||||
{
|
||||
noInterrupts();
|
||||
PulseWidth_us=_Width_us;
|
||||
PulseWidth_us = _Width_us;
|
||||
interrupts();
|
||||
Ret=_Available && (PulseWidth_us>=_Min_us) && (PulseWidth_us<=_Max_us);
|
||||
Ret=_Available && (PulseWidth_us >= _Min_us) && (PulseWidth_us <= _Max_us);
|
||||
_Available=0;
|
||||
}
|
||||
return(Ret);
|
||||
}
|
||||
#ifdef SOFT_RC_PULSE_IN_TIMEOUT_SUPPORT
|
||||
boolean SoftRcPulseIn::timeout(uint8_t TimeoutMs, uint8_t *CurrentState)
|
||||
{
|
||||
uint8_t CurMs, Ret = 0;
|
||||
|
||||
CurMs = (uint8_t)(millis() & 0x000000FF);
|
||||
if((uint8_t)(CurMs - _LastTimeStampMs) >= TimeoutMs)
|
||||
{
|
||||
*CurrentState = digitalRead(_Pin);
|
||||
Ret = 1;
|
||||
}
|
||||
return(Ret);
|
||||
}
|
||||
#endif
|
||||
uint16_t SoftRcPulseIn::width_us(void)
|
||||
{
|
||||
uint16_t PulseWidth_us;
|
||||
noInterrupts();
|
||||
PulseWidth_us=_Width_us;
|
||||
PulseWidth_us = _Width_us;
|
||||
interrupts();
|
||||
return(PulseWidth_us);
|
||||
}
|
||||
@ -98,13 +114,16 @@ SoftRcPulseIn *RcPulseIn;
|
||||
if(digitalRead(RcPulseIn->_Pin))
|
||||
{
|
||||
/* High level, rising edge: start chrono */
|
||||
RcPulseIn->_Start_us=micros();
|
||||
RcPulseIn->_Start_us = micros();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Low level, falling edge: stop chrono */
|
||||
RcPulseIn->_Width_us=micros()-RcPulseIn->_Start_us;
|
||||
RcPulseIn->_Available=1;
|
||||
RcPulseIn->_Width_us = micros() - RcPulseIn->_Start_us;
|
||||
RcPulseIn->_Available = 1;
|
||||
#ifdef SOFT_RC_PULSE_IN_TIMEOUT_SUPPORT
|
||||
RcPulseIn->_LastTimeStampMs = (uint8_t)(millis() & 0x000000FF);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
/*
|
||||
English: by RC Navy (2012)
|
||||
English: by RC Navy (2012-2015)
|
||||
=======
|
||||
<SoftRcPulseIn>: an asynchronous library to read Input Pulse Width from standard Hobby Radio-Control. This library is a non-blocking version of pulseIn().
|
||||
http://p.loussouarn.free.fr
|
||||
|
||||
Francais: par RC Navy (2012)
|
||||
Francais: par RC Navy (2012-2015)
|
||||
========
|
||||
<SoftRcPulseIn>: une librairie asynchrone pour lire les largeur d'impulsions des Radio-Commandes standards. Cette librairie est une version non bloquante de pulsIn().
|
||||
http://p.loussouarn.free.fr
|
||||
@ -23,6 +23,8 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define SOFT_RC_PULSE_IN_TIMEOUT_SUPPORT
|
||||
|
||||
class SoftRcPulseIn
|
||||
{
|
||||
public:
|
||||
@ -31,8 +33,9 @@ class SoftRcPulseIn
|
||||
static int LibRevision(void);
|
||||
static char *LibTextVersionRevision(void);
|
||||
static void SoftRcPulseInInterrupt(void);
|
||||
uint8_t attach(uint8_t Pin, uint16_t PulseMin_us=600, uint16_t PulseMax_us=2400);
|
||||
uint8_t attach(uint8_t Pin, uint16_t PulseMin_us = 600, uint16_t PulseMax_us = 2400);
|
||||
boolean available();
|
||||
boolean timeout(uint8_t TimeoutMs, uint8_t *State);
|
||||
uint16_t width_us();
|
||||
private:
|
||||
class SoftRcPulseIn *next;
|
||||
@ -45,6 +48,9 @@ class SoftRcPulseIn
|
||||
uint32_t _Start_us;
|
||||
uint32_t _Width_us;
|
||||
boolean _Available;
|
||||
#ifdef SOFT_RC_PULSE_IN_TIMEOUT_SUPPORT
|
||||
uint8_t _LastTimeStampMs;
|
||||
#endif
|
||||
};
|
||||
/*******************************************************/
|
||||
/* Application Programming Interface (API) en Francais */
|
||||
|
@ -52,6 +52,8 @@
|
||||
#define RX_AUX_GEAR_PIN 0 //Choose here the pin for the RC signal
|
||||
#define DEBUG_TX_RX_PIN 1 //Adjust here your Tx/Rx debug pin (Do NOT work on Digispark PIN 5: choose another PIN)
|
||||
|
||||
#define SERIAL_BAUD_RATE 57600 //Adjust rate here
|
||||
|
||||
SoftRcPulseIn RxAuxGear; //Choose a name for your RC channel signal
|
||||
|
||||
SoftSerial MyDbgSerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); //true allows to connect to a regular RS232 without RS232 line driver
|
||||
@ -60,7 +62,7 @@ void setup()
|
||||
{
|
||||
RxAuxGear.attach(RX_AUX_GEAR_PIN);
|
||||
|
||||
MyDbgSerial.begin(38400); //Do NOT forget to setup your terminal at 38400 (eg: arduino IDE serial monitor)
|
||||
MyDbgSerial.begin(SERIAL_BAUD_RATE); //Do NOT forget to setup your terminal at same baud rate (eg: arduino IDE serial monitor)
|
||||
MyDbgSerial.txMode(); //Before sending a message, switch to txMode
|
||||
MyDbgSerial.print(F("SoftRcPulseIn lib V"));MyDbgSerial.print(SoftRcPulseIn::LibTextVersionRevision());MyDbgSerial.println(F(" demo"));
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ boolean LedState=HIGH;
|
||||
|
||||
void setup()
|
||||
{
|
||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__)
|
||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny167__)
|
||||
Serial.begin(9600);
|
||||
Serial.print("SoftRcPulseIn library V");Serial.print(SoftRcPulseIn::LibTextVersionRevision());Serial.print(" demo"); /* For arduino UNO which has an hardware UART, display the library version in the console */
|
||||
#endif
|
||||
@ -74,8 +74,8 @@ static uint16_t Width_us=NEUTRAL_US; /* Static to keep the value at the next loo
|
||||
ServoMotor[INVERTED].write_us((NEUTRAL_US*2)-Width_us); /* Inverted Signal */
|
||||
SoftRcPulseOut::refresh(NOW); /* NOW argument (=1) allows to synchronize outgoing pulses with incoming pulses */
|
||||
RxPulseStartMs=millis(); /* Restart the Chrono for Pulse */
|
||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__)
|
||||
Serial.print("Pulse=");Serial.println(Largeur_us); /* For arduino UNO which has an hardware UART, display the library version in the console */
|
||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny167__)
|
||||
Serial.print("Pulse=");Serial.println(Width_us); /* For arduino UNO which has an hardware UART, display the library version in the console */
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@ -18,6 +18,7 @@ attach KEYWORD2
|
||||
attache KEYWORD2
|
||||
available KEYWORD2
|
||||
disponible KEYWORD2
|
||||
timeout KEYWORD2
|
||||
width_us KEYWORD2
|
||||
largeur_us KEYWORD2
|
||||
|
||||
|
@ -0,0 +1,67 @@
|
||||
SoftRcPulseOut library
|
||||
======================
|
||||
|
||||
**SoftRcPulseOut** is pseudo-asynchronous library designed to generate RC pulse signals. RC pulse signals are intended to command servos, **E**lectronic **S**peed **C**ontrollers (**ESC**), Brushless Controllers and any devices expecting such a command signal.
|
||||
|
||||
Some examples of use cases:
|
||||
-------------------------
|
||||
* **Servo/ESC/Brushless Controller tester**
|
||||
* **Servo sequencer** (look at RcSeq library which uses _SoftRcPulseOut_)
|
||||
* **Robot wheels using modified Servo to support 360° rotation**
|
||||
* **RC pulse stretcher** (in conjunction with **SoftRcPulseIn** library)
|
||||
|
||||
Supported Arduinos:
|
||||
------------------
|
||||
* **ATmega368 (UNO)**
|
||||
* **ATmega2560 (MEGA)**
|
||||
* **ATtiny84 (Standalone)**
|
||||
* **ATtiny85 (Standalone or Digispark)**
|
||||
* **ATtiny167 (Digispark pro)**
|
||||
|
||||
Tip and Tricks:
|
||||
--------------
|
||||
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
|
||||
|
||||
API/methods:
|
||||
-----------
|
||||
* The **SoftRcPulseOut** library uses the same API as the regular **SoftwareServo** library:
|
||||
* attach()
|
||||
* attached()
|
||||
* detach()
|
||||
* write()
|
||||
* read()
|
||||
* setMinimumPulse()
|
||||
* setMaximumPulse()
|
||||
* refresh()
|
||||
|
||||
* Two additional methods allow using µs rather than angle in ° :
|
||||
* write_us()
|
||||
* read_us()
|
||||
|
||||
* Methods for version management:
|
||||
* LibVersion
|
||||
* LibRevision
|
||||
* LibTextVersionRevision
|
||||
|
||||
* Synchronization:
|
||||
* By giving **_1_** or **_true_** as optional argument for the **SoftRcPulseOut::refresh()** method, the pulses are refreshed immediately (without waiting for the usual 20ms).
|
||||
|
||||
* the **SoftRcPulseOut::refresh()** method returns **_1_** or **_true_** when the pulses have been refreshed. Testing this return value provides a 20ms timer.
|
||||
|
||||
Design considerations:
|
||||
---------------------
|
||||
The **SoftRcPulseOut** library relies on a 8 bit timer. This allows using it even on little MCU (such as ATtiny85) which do not have any 16 bit timer.
|
||||
|
||||
Whereas a 8 bit timer is used for pulse generation, the jitter is limited by using anticipated interrupt masking.
|
||||
|
||||
Interrups are only masked during rising and falling edges of the pulse signals.
|
||||
|
||||
CAUTION:
|
||||
-------
|
||||
The end user shall also use asynchronous programmation method in the loop() function (not too long blocking functions such as delay(1000): the **SoftRcPulseOut::refresh()** method shall be called at least every 50ms).
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
||||
|
@ -1,13 +1,15 @@
|
||||
#include "SoftRcPulseOut.h"
|
||||
/*
|
||||
Update 01/03/2013: add support for DigiSpark (http://digistump.com): automatic Timer selection (RC Navy: p.loussouarn.free.fr)
|
||||
|
||||
Update 01/03/2013: add support for Digispark (http://digistump.com): automatic Timer selection (RC Navy: p.loussouarn.free.fr)
|
||||
Update 19/08/2014: usage with write_us and read_us fixed
|
||||
|
||||
English: by RC Navy (2012)
|
||||
=======
|
||||
<SoftRcPulseOut>: a library mainly based on the <SoftwareServo> library, but with a better pulse generation to limit jitter.
|
||||
It supports the same methods as <SoftwareServo>.
|
||||
It also support Pulse Width order given in microseconds. The current Pulse Width can also be read in microseconds.
|
||||
The refresh method can admit an optionnal argument (force). If SoftRcPulseOut::refresh(1) is called, the refresh is forced even if 20 ms are not elapsed.
|
||||
The refresh() method returns 1 if refresh done (can be used for synchro and/or for 20ms timer).
|
||||
http://p.loussouarn.free.fr
|
||||
|
||||
Francais: par RC Navy (2012)
|
||||
@ -16,6 +18,7 @@
|
||||
Elle supporte les memes methodes que <SoftwareServo>.
|
||||
Elle supporte egalement une consigne de largeur d'impulsion passee en microseconde. La largeur de l'impulsion courante peut egalement etre lue en microseconde.
|
||||
La methode refresh peut admettre un parametre optionnel (force). Si SoftRcPulseOut::resfresh(1) est appelee, le refresh est force meme si 20 ms ne se sont pas ecoulee.
|
||||
La methode refresh() retourne 1 si refresh effectue (peut etre utilise pour synhro et/ou 20ms timer).
|
||||
http://p.loussouarn.free.fr
|
||||
*/
|
||||
|
||||
@ -26,7 +29,7 @@
|
||||
#if (TIMER_TO_USE_FOR_MILLIS==1)
|
||||
#define SOFT_RC_PULSE_OUT_TCNT TCNT1 //For example for ATtiny85
|
||||
#else
|
||||
#define SOFT_RC_PULSE_OUT_TCNT TCNT0 //For example for ATtiny84
|
||||
#define SOFT_RC_PULSE_OUT_TCNT TCNT0 //For example for ATtiny84 and ATtiny167
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -34,60 +37,69 @@ SoftRcPulseOut *SoftRcPulseOut::first;
|
||||
|
||||
#define NO_ANGLE (0xff)
|
||||
|
||||
SoftRcPulseOut::SoftRcPulseOut() : pin(0),angle(NO_ANGLE),pulse0(0),min16(34),max16(150),next(0)
|
||||
SoftRcPulseOut::SoftRcPulseOut() : pin(0), angle(NO_ANGLE), pulse0(0), min16(34), max16(150), next(0)
|
||||
{}
|
||||
|
||||
void SoftRcPulseOut::setMinimumPulse(uint16_t t)
|
||||
{
|
||||
min16 = t/16;
|
||||
min16 = t / 16;
|
||||
}
|
||||
|
||||
void SoftRcPulseOut::setMaximumPulse(uint16_t t)
|
||||
{
|
||||
max16 = t/16;
|
||||
max16 = t / 16;
|
||||
}
|
||||
|
||||
uint8_t SoftRcPulseOut::attach(int pinArg)
|
||||
{
|
||||
pin = pinArg;
|
||||
angle = NO_ANGLE;
|
||||
pin = pinArg;
|
||||
angle = NO_ANGLE;
|
||||
pulse0 = 0;
|
||||
next = first;
|
||||
first = this;
|
||||
digitalWrite(pin,0);
|
||||
pinMode(pin,OUTPUT);
|
||||
return 1;
|
||||
next = first;
|
||||
first = this;
|
||||
digitalWrite(pin, LOW);
|
||||
pinMode(pin, OUTPUT);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void SoftRcPulseOut::detach()
|
||||
{
|
||||
for ( SoftRcPulseOut **p = &first; *p != 0; p = &((*p)->next) ) {
|
||||
if ( *p == this) {
|
||||
*p = this->next;
|
||||
this->next = 0;
|
||||
return;
|
||||
}
|
||||
for ( SoftRcPulseOut **p = &first; *p != 0; p = &((*p)->next) )
|
||||
{
|
||||
if ( *p == this )
|
||||
{
|
||||
*p = this->next;
|
||||
this->next = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoftRcPulseOut::write(int angleArg)
|
||||
{
|
||||
if ( angleArg < 0) angleArg = 0;
|
||||
if ( angleArg < 0) angleArg = 0;
|
||||
if ( angleArg > 180) angleArg = 180;
|
||||
angle = angleArg;
|
||||
// bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
|
||||
// That 64L on the end is the TCNT0 prescaler, it will need to change if the clock's prescaler changes,
|
||||
// but then there will likely be an overflow problem, so it will have to be handled by a human.
|
||||
#ifdef TIMER0_TICK_EVERY_X_CYCLES
|
||||
pulse0 = (min16*16L*clockCyclesPerMicrosecond() + (max16-min16)*(16L*clockCyclesPerMicrosecond())*angle/180L)/TIMER0_TICK_EVERY_X_CYCLES;
|
||||
#ifdef MS_TIMER_TICK_EVERY_X_CYCLES
|
||||
pulse0 = (min16 * 16L * clockCyclesPerMicrosecond() + (max16 - min16) * (16L * clockCyclesPerMicrosecond()) * angle / 180L) / MS_TIMER_TICK_EVERY_X_CYCLES;
|
||||
#else
|
||||
pulse0 = (min16*16L*clockCyclesPerMicrosecond() + (max16-min16)*(16L*clockCyclesPerMicrosecond())*angle/180L)/64L;
|
||||
pulse0 = (min16 * 16L * clockCyclesPerMicrosecond() + (max16 - min16) * (16L * clockCyclesPerMicrosecond()) * angle / 180L) / 64L;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SoftRcPulseOut::write_us(int PulseWidth_us)
|
||||
void SoftRcPulseOut::write_us(uint16_t PulseWidth_us)
|
||||
{
|
||||
SoftRcPulseOut::write(map(PulseWidth_us,min16*16,max16*16,0,180));
|
||||
if ( PulseWidth_us < (min16 * 16)) PulseWidth_us = (min16 * 16);
|
||||
if ( PulseWidth_us > (max16 * 16)) PulseWidth_us = (max16 * 16);
|
||||
#ifdef MS_TIMER_TICK_EVERY_X_CYCLES
|
||||
pulse0 = (PulseWidth_us * clockCyclesPerMicrosecond()) / MS_TIMER_TICK_EVERY_X_CYCLES;
|
||||
#else
|
||||
pulse0 = (PulseWidth_us * clockCyclesPerMicrosecond()) / 64L;
|
||||
#endif
|
||||
angle = map(PulseWidth_us, min16 * 16, max16 * 16, 0, 180);
|
||||
}
|
||||
|
||||
uint8_t SoftRcPulseOut::read()
|
||||
@ -95,114 +107,123 @@ uint8_t SoftRcPulseOut::read()
|
||||
return angle;
|
||||
}
|
||||
|
||||
uint8_t SoftRcPulseOut::read_us()
|
||||
uint16_t SoftRcPulseOut::read_us()
|
||||
{
|
||||
return map(angle,0,180,min16*16,max16*16);
|
||||
#ifdef MS_TIMER_TICK_EVERY_X_CYCLES
|
||||
return((pulse0 * MS_TIMER_TICK_EVERY_X_CYCLES) / clockCyclesPerMicrosecond());
|
||||
#else
|
||||
return((pulse0 * 64L) / clockCyclesPerMicrosecond());
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t SoftRcPulseOut::attached()
|
||||
{
|
||||
for ( SoftRcPulseOut *p = first; p != 0; p = p->next ) {
|
||||
if ( p == this) return 1;
|
||||
}
|
||||
return 0;
|
||||
for ( SoftRcPulseOut *p = first; p != 0; p = p->next )
|
||||
{
|
||||
if ( p == this) return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint8_t SoftRcPulseOut::refresh(bool force /* = false */)
|
||||
{
|
||||
uint8_t RefreshDone=0;
|
||||
uint8_t count = 0, i = 0;
|
||||
uint16_t base = 0;
|
||||
SoftRcPulseOut *p;
|
||||
static unsigned long lastRefresh = 0;
|
||||
unsigned long m = millis();
|
||||
if(!force)
|
||||
{
|
||||
// if we haven't wrapped millis, and 20ms have not passed, then don't do anything
|
||||
if ( m >= lastRefresh && m < lastRefresh + 20) return(RefreshDone);
|
||||
}
|
||||
RefreshDone=1; //Ok: Refresh will be performed
|
||||
lastRefresh = m;
|
||||
uint8_t RefreshDone = 0;
|
||||
uint8_t count = 0, i = 0;
|
||||
uint16_t base = 0;
|
||||
SoftRcPulseOut *p;
|
||||
static uint32_t lastRefresh = 0;
|
||||
uint32_t m = millis();
|
||||
|
||||
if(!force)
|
||||
{
|
||||
// if we haven't wrapped millis, and 20ms have not passed, then don't do anything
|
||||
if ( (m - lastRefresh) < 20UL ) return(RefreshDone);
|
||||
}
|
||||
RefreshDone = 1; //Ok: Refresh will be performed
|
||||
lastRefresh = m;
|
||||
|
||||
for ( p = first; p != 0; p = p->next ) if ( p->pulse0) count++;
|
||||
if ( count == 0) return(RefreshDone);
|
||||
for ( p = first; p != 0; p = p->next ) if ( p->pulse0 ) count++;
|
||||
if ( count == 0 ) return(RefreshDone);
|
||||
|
||||
// gather all the SoftRcPulseOuts in an array
|
||||
SoftRcPulseOut *s[count];
|
||||
for ( p = first; p != 0; p = p->next ) if ( p->pulse0) s[i++] = p;
|
||||
// gather all the SoftRcPulseOuts in an array
|
||||
SoftRcPulseOut *s[count];
|
||||
for ( p = first; p != 0; p = p->next ) if ( p->pulse0) s[i++] = p;
|
||||
|
||||
// bubblesort the SoftRcPulseOuts by pulse time, ascending order
|
||||
s[0]->ItMasked=0;
|
||||
for(;;)
|
||||
{
|
||||
uint8_t moved = 0;
|
||||
for ( i = 1; i < count; i++)
|
||||
{
|
||||
s[i]->ItMasked=0;
|
||||
if ( s[i]->pulse0 < s[i-1]->pulse0)
|
||||
{
|
||||
SoftRcPulseOut *t = s[i];
|
||||
s[i] = s[i-1];
|
||||
s[i-1] = t;
|
||||
moved = 1;
|
||||
}
|
||||
}
|
||||
if ( !moved) break;
|
||||
// bubblesort the SoftRcPulseOuts by pulse time, ascending order
|
||||
s[0]->ItMasked = 0;
|
||||
for(;;)
|
||||
{
|
||||
uint8_t moved = 0;
|
||||
for ( i = 1; i < count; i++ )
|
||||
{
|
||||
s[i]->ItMasked = 0;
|
||||
if ( s[i]->pulse0 < s[i - 1]->pulse0 )
|
||||
{
|
||||
SoftRcPulseOut *t = s[i];
|
||||
s[i] = s[i - 1];
|
||||
s[i - 1] = t;
|
||||
moved = 1;
|
||||
}
|
||||
}
|
||||
for ( i = 1; i < count; i++)
|
||||
if ( !moved ) break;
|
||||
}
|
||||
for ( i = 1; i < count; i++ )
|
||||
{
|
||||
if ( abs(s[i]->pulse0 - s[i - 1]->pulse0) <= 5)
|
||||
{
|
||||
s[i]->ItMasked = 1; /* 2 consecutive Pulses are close each other, so do not unmask interrupts between Pulses */
|
||||
}
|
||||
}
|
||||
// turn on all the pins
|
||||
// Note the timing error here... when you have many SoftwareServos going, the
|
||||
// ones at the front will get a pulse that is a few microseconds too long.
|
||||
// Figure about 4uS/SoftRcPulseOut after them. This could be compensated, but I feel
|
||||
// it is within the margin of error of software SoftRcPulseOuts that could catch
|
||||
// an extra interrupt handler at any time.
|
||||
noInterrupts();
|
||||
for ( i = 0; i < count; i++ ) digitalWrite( s[i]->pin, 1);
|
||||
interrupts();
|
||||
|
||||
uint8_t start = SOFT_RC_PULSE_OUT_TCNT;
|
||||
uint8_t now = start;
|
||||
uint8_t last = now;
|
||||
|
||||
// Now wait for each pin's time in turn..
|
||||
for ( i = 0; i < count; i++ )
|
||||
{
|
||||
uint16_t go = start + s[i]->pulse0;
|
||||
#ifndef MS_TIMER_TICK_EVERY_X_CYCLES
|
||||
uint16_t it = go - 4; /* 4 Ticks is OK for UNO @ 16MHz with default prescaler*/ /* Mask Interruptions just before setting down the pin */
|
||||
#else
|
||||
uint16_t it = go - max(4, (256 / MS_TIMER_TICK_EVERY_X_CYCLES)); /* 4 Ticks is OK for UNO @ 16MHz */ /* Mask Interruptions just before setting down the pin */
|
||||
#endif
|
||||
// loop until we reach or pass 'go' time: this is a blocking loop (max 2400us) except for non masked ISR (between edges)
|
||||
for (;;)
|
||||
{
|
||||
now = SOFT_RC_PULSE_OUT_TCNT;
|
||||
if ( now < last ) base += 256;
|
||||
last = now;
|
||||
if( !s[i]->ItMasked )
|
||||
{
|
||||
if( base + now > it)
|
||||
{
|
||||
if ( abs(s[i]->pulse0 - s[i-1]->pulse0)<=5)
|
||||
{
|
||||
s[i]->ItMasked=1; /* 2 consecutive Pulses are close each other, so do not unmask interrupts between Pulses */
|
||||
}
|
||||
noInterrupts();
|
||||
s[i]->ItMasked = 1;
|
||||
}
|
||||
// turn on all the pins
|
||||
// Note the timing error here... when you have many SoftwareServos going, the
|
||||
// ones at the front will get a pulse that is a few microseconds too long.
|
||||
// Figure about 4uS/SoftRcPulseOut after them. This could be compensated, but I feel
|
||||
// it is within the margin of error of software SoftRcPulseOuts that could catch
|
||||
// an extra interrupt handler at any time.
|
||||
noInterrupts();
|
||||
for ( i = 0; i < count; i++) digitalWrite( s[i]->pin, 1);
|
||||
interrupts();
|
||||
|
||||
uint8_t start = SOFT_RC_PULSE_OUT_TCNT;
|
||||
uint8_t now = start;
|
||||
uint8_t last = now;
|
||||
|
||||
// Now wait for each pin's time in turn..
|
||||
for ( i = 0; i < count; i++)
|
||||
}
|
||||
if ( base + now > go )
|
||||
{
|
||||
digitalWrite( s[i]->pin, 0);
|
||||
if( (i + 1) < count )
|
||||
{
|
||||
uint16_t go = start + s[i]->pulse0;
|
||||
uint16_t it = go - 4; /* 4 Ticks is OK for UNO @ 16MHz */ /* Mask Interruptions just before setting down the pin */
|
||||
|
||||
// loop until we reach or pass 'go' time
|
||||
for (;;)
|
||||
{
|
||||
now = SOFT_RC_PULSE_OUT_TCNT;
|
||||
if ( now < last) base += 256;
|
||||
last = now;
|
||||
if(!s[i]->ItMasked)
|
||||
{
|
||||
if( base + now > it)
|
||||
{
|
||||
noInterrupts();
|
||||
s[i]->ItMasked=1;
|
||||
}
|
||||
}
|
||||
if ( base + now > go)
|
||||
{
|
||||
digitalWrite( s[i]->pin,0);
|
||||
if((i+1)<count)
|
||||
{
|
||||
if(!s[i+1]->ItMasked)
|
||||
{
|
||||
interrupts();
|
||||
}
|
||||
}else interrupts();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(RefreshDone);
|
||||
if( !s[i + 1]->ItMasked )
|
||||
{
|
||||
interrupts();
|
||||
}
|
||||
}else interrupts();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(RefreshDone);
|
||||
}
|
||||
|
@ -2,14 +2,16 @@
|
||||
#define SoftRcPulseOut_h
|
||||
|
||||
/*
|
||||
Update 01/03/2013: add support for DigiSpark (http://digistump.com): automatic Timer selection (RC Navy: p.loussouarn.free.fr)
|
||||
|
||||
Update 01/03/2013: add support for Digispark (http://digistump.com): automatic Timer selection (RC Navy: p.loussouarn.free.fr)
|
||||
Update 19/08/2014: usage with write_us and read_us fixed and optimized for highest resolution
|
||||
|
||||
English: by RC Navy (2012)
|
||||
=======
|
||||
<SoftRcPulseOut>: a library mainly based on the <SoftwareServo> library, but with a better pulse generation to limit jitter.
|
||||
It supports the same methods as <SoftwareServo>.
|
||||
It also support Pulse Width order given in microseconds. The current Pulse Width can also be read in microseconds.
|
||||
The refresh method can admit an optionnal argument (force). If SoftRcPulseOut::refresh(1) is called, the refresh is forced even if 20 ms are not elapsed.
|
||||
The refresh() method returns 1 if refresh done (can be used for synchro and/or for 20ms timer).
|
||||
http://p.loussouarn.free.fr
|
||||
|
||||
Francais: par RC Navy (2012)
|
||||
@ -18,6 +20,7 @@
|
||||
Elle supporte les memes methodes que <SoftwareServo>.
|
||||
Elle supporte egalement une consigne de largeur d'impulsion passee en microseconde. La largeur de l'impulsion courante peut egalement etre lue en microseconde.
|
||||
La methode refresh peut admettre un parametre optionnel (force). Si SoftRcPulseOut::resfresh(1) est appelee, le refresh est force meme si 20 ms ne se sont pas ecoulee.
|
||||
La methode refresh() retourne 1 si refresh effectue (peut etre utilise pour synhro et/ou 20ms timer).
|
||||
http://p.loussouarn.free.fr
|
||||
*/
|
||||
|
||||
@ -32,28 +35,40 @@
|
||||
class SoftRcPulseOut
|
||||
{
|
||||
private:
|
||||
boolean ItMasked;
|
||||
uint8_t pin;
|
||||
uint8_t angle; // in degrees
|
||||
uint16_t pulse0; // pulse width in TCNT0 counts
|
||||
uint8_t min16; // minimum pulse, 16uS units (default is 34)
|
||||
uint8_t max16; // maximum pulse, 16uS units, 0-4ms range (default is 150)
|
||||
class SoftRcPulseOut *next;
|
||||
static SoftRcPulseOut* first;
|
||||
boolean ItMasked;
|
||||
uint8_t pin;
|
||||
uint8_t angle; // in degrees
|
||||
uint16_t pulse0; // pulse width in TCNT0 counts
|
||||
uint8_t min16; // minimum pulse, 16uS units (default is 34)
|
||||
uint8_t max16; // maximum pulse, 16uS units, 0-4ms range (default is 150)
|
||||
class SoftRcPulseOut *next;
|
||||
static SoftRcPulseOut *first;
|
||||
public:
|
||||
SoftRcPulseOut();
|
||||
uint8_t attach(int); // attach to a pin, sets pinMode, returns 0 on failure, won't
|
||||
// position the servo until a subsequent write() happens
|
||||
void detach();
|
||||
void write(int); // specify the angle in degrees, 0 to 180
|
||||
void write_us(int); // specify the angle in microseconds, 500 to 2500
|
||||
uint8_t read(); // return the current angle
|
||||
uint8_t read_us(); // return the current pulse with in microseconds
|
||||
uint8_t attached();
|
||||
void setMinimumPulse(uint16_t); // pulse length for 0 degrees in microseconds, 540uS default
|
||||
void setMaximumPulse(uint16_t); // pulse length for 180 degrees in microseconds, 2400uS default
|
||||
static uint8_t refresh(bool force = false); // must be called at least every 50ms or so to keep servo alive
|
||||
// you can call more often, it won't happen more than once every 20ms
|
||||
uint8_t attach(int); // attach to a pin, sets pinMode, returns 0 on failure, won't
|
||||
// position the servo until a subsequent write() happens
|
||||
void detach();
|
||||
void write(int); // specify the angle in degrees, 0 to 180
|
||||
void write_us(uint16_t); // specify the angle in microseconds, 500 to 2500
|
||||
uint8_t read(); // return the current angle
|
||||
uint16_t read_us(); // return the current pulse with in microseconds
|
||||
uint8_t attached();
|
||||
void setMinimumPulse(uint16_t); // pulse length for 0 degrees in microseconds, 540uS default
|
||||
void setMaximumPulse(uint16_t); // pulse length for 180 degrees in microseconds, 2400uS default
|
||||
static uint8_t refresh(bool force = false);// must be called at least every 50ms or so to keep servo alive
|
||||
// you can call more often, it won't happen more than once every 20ms
|
||||
};
|
||||
|
||||
/* Methodes en Francais English native methods */
|
||||
#define attache attach
|
||||
#define detache detach
|
||||
#define ecrit write
|
||||
#define ecrit_us write_us
|
||||
#define lit read
|
||||
#define lit_us read_us
|
||||
#define estAttache attached
|
||||
#define definitImpulsionMinimum setMinimumPulse
|
||||
#define definitImpulsionMaximum setMaximumPulse
|
||||
#define rafraichit refresh
|
||||
|
||||
#endif
|
||||
|
@ -19,6 +19,8 @@ SoftRcPulseOut myservo; // create servo object to control a servo
|
||||
|
||||
#define REFRESH_PERIOD_MS 20
|
||||
|
||||
#define NOW 1
|
||||
|
||||
int val; // variable to read the value from the analog pin
|
||||
|
||||
void setup()
|
||||
@ -32,6 +34,6 @@ void loop()
|
||||
val = map(val, 0, 1023, 0, 179); // scale it to use it with the servo (value between 0 and 180)
|
||||
myservo.write(val); // sets the servo position according to the scaled value
|
||||
delay(REFRESH_PERIOD_MS); // waits for the servo to get there
|
||||
SoftRcPulseOut::refresh(); // generates the servo pulse
|
||||
SoftRcPulseOut::refresh(NOW); // generates the servo pulse Now
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ boolean LedState=HIGH;
|
||||
|
||||
void setup()
|
||||
{
|
||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__)
|
||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny167__)
|
||||
Serial.begin(9600);
|
||||
Serial.print("SoftRcPulseIn library V");Serial.print(SoftRcPulseIn::LibTextVersionRevision());Serial.print(" demo"); /* For arduino UNO which has an hardware UART, display the library version in the console */
|
||||
#endif
|
||||
@ -74,8 +74,8 @@ static uint16_t Width_us=NEUTRAL_US; /* Static to keep the value at the next loo
|
||||
ServoMotor[INVERTED].write_us((NEUTRAL_US*2)-Width_us); /* Inverted Signal */
|
||||
SoftRcPulseOut::refresh(NOW); /* NOW argument (=1) allows to synchronize outgoing pulses with incoming pulses */
|
||||
RxPulseStartMs=millis(); /* Restart the Chrono for Pulse */
|
||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__)
|
||||
Serial.print("Pulse=");Serial.println(Largeur_us); /* For arduino UNO which has an hardware UART, display the library version in the console */
|
||||
#if !defined(__AVR_ATtiny24__) && !defined(__AVR_ATtiny44__) && !defined(__AVR_ATtiny84__) && !defined(__AVR_ATtiny25__) && !defined(__AVR_ATtiny45__) && !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny167__)
|
||||
Serial.print("Pulse=");Serial.println(Width_us); /* For arduino UNO which has an hardware UART, display the library version in the console */
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@ -12,6 +12,8 @@ SoftRcPulseOut myservo; // create servo object to control a servo
|
||||
|
||||
#define REFRESH_PERIOD_MS 20
|
||||
|
||||
#define NOW 1
|
||||
|
||||
int pos = 0; // variable to store the servo position
|
||||
|
||||
void setup()
|
||||
@ -26,12 +28,12 @@ void loop()
|
||||
{ // in steps of 1 degree
|
||||
myservo.write(pos); // tell servo to go to position in variable 'pos'
|
||||
delay(REFRESH_PERIOD_MS); // waits 20ms for refresh period
|
||||
SoftRcPulseOut::refresh(1); // generates the servo pulse
|
||||
SoftRcPulseOut::refresh(NOW); // generates the servo pulse Now
|
||||
}
|
||||
for(pos = 180; pos>=1; pos-=1) // goes from 180 degrees to 0 degrees
|
||||
{
|
||||
myservo.write(pos); // tell servo to go to position in variable 'pos'
|
||||
delay(REFRESH_PERIOD_MS); // waits 20ms for for refresh period
|
||||
SoftRcPulseOut::refresh(1); // generates the servo pulse
|
||||
SoftRcPulseOut::refresh(NOW); // generates the servo pulse Now
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
// SweepNoDelay
|
||||
// by RC Navy (http://p.loussouarn.free.fr/arduino/arduino.html>)
|
||||
// This sketch can work with ATtiny and Arduino UNO, MEGA, etc...
|
||||
// This example code is in the public domain.
|
||||
|
||||
#include <SoftRcPulseOut.h>
|
||||
|
||||
SoftRcPulseOut myservo; // create servo object to control a servo
|
||||
// a maximum of eight servo objects can be created
|
||||
#define SERVO_PIN 0
|
||||
|
||||
#define UP_DIRECTION +1
|
||||
#define DOWN_DIRECTION -1
|
||||
|
||||
#define POS_MIN 0
|
||||
#define POS_MAX 180
|
||||
|
||||
int pos = POS_MIN; // variable to store the servo position
|
||||
int step = UP_DIRECTION;
|
||||
|
||||
void setup()
|
||||
{
|
||||
myservo.attach(SERVO_PIN); // attaches the servo on pin defined by SERVO_PIN to the servo object
|
||||
myservo.write(pos);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (SoftRcPulseOut::refresh()) // refresh() returns 1 every 20ms (after pulse update)
|
||||
{
|
||||
// We arrive here every 20ms
|
||||
pos += step;
|
||||
if(pos >= POS_MAX) step = DOWN_DIRECTION; //180 degrees reached -> Change direction
|
||||
if(pos <= POS_MIN) step = UP_DIRECTION; // 0 degrees reached -> Change direction
|
||||
myservo.write(pos);
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ SoftRcPulseOut myservo; // create servo object to control a servo
|
||||
|
||||
#define REFRESH_PERIOD_MS 20
|
||||
|
||||
#define NOW 1
|
||||
|
||||
#define MOY_SUR_1_VALEUR 0
|
||||
#define MOY_SUR_2_VALEURS 1
|
||||
@ -46,8 +47,8 @@ static int ValMoyennee;
|
||||
val = analogRead(POT_PIN); // reads the value of the potentiometer (value between 0 and 1023)
|
||||
val = map(val, 0, 1023, 0, 179); // scale it to use it with the servo (value between 0 and 180)
|
||||
MOYENNE(ValMoyennee,val,TAUX_DE_MOYENNAGE);//If there is lots of noise: average with TAUX_DE_MOYENNAGE
|
||||
myservo.write(ValMoyennee); // sets the servo position according to the scaled value
|
||||
myservo.write(ValMoyennee); // sets the servo position according to the scaled value
|
||||
delay(REFRESH_PERIOD_MS); // waits for the servo to get there
|
||||
SoftRcPulseOut::refresh(); // generates the servo pulse
|
||||
SoftRcPulseOut::refresh(NOW); // generates the servo pulse
|
||||
}
|
||||
|
||||
|
@ -6,21 +6,31 @@
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
SoftRcPulseOut KEYWORD1
|
||||
SoftRcPulseOut KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
attach KEYWORD2
|
||||
detach KEYWORD2
|
||||
write KEYWORD2
|
||||
write_us KEYWORD2
|
||||
read KEYWORD2
|
||||
read_us KEYWORD2
|
||||
attached KEYWORD2
|
||||
setMinimumPulse KEYWORD2
|
||||
setMaximumPulse KEYWORD2
|
||||
refresh KEYWORD2
|
||||
attach KEYWORD2
|
||||
attache KEYWORD2
|
||||
detach KEYWORD2
|
||||
detache KEYWORD2
|
||||
write KEYWORD2
|
||||
ecrit KEYWORD2
|
||||
write_us KEYWORD2
|
||||
ecrit_us KEYWORD2
|
||||
read KEYWORD2
|
||||
lit KEYWORD2
|
||||
read_us KEYWORD2
|
||||
lit_us KEYWORD2
|
||||
attached KEYWORD2
|
||||
estAttache KEYWORD2
|
||||
setMinimumPulse KEYWORD2
|
||||
definitImpulsionMinimum KEYWORD2
|
||||
setMaximumPulse KEYWORD2
|
||||
definitImpulsionMaximum KEYWORD2
|
||||
refresh KEYWORD2
|
||||
rafraichit KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
|
@ -0,0 +1,64 @@
|
||||
SoftSerial library
|
||||
==================
|
||||
|
||||
The **SoftSerial** library is exactly the same as the **SoftwareSerial** library but used with the **TinyPinChange** library which allows to share
|
||||
the "Pin Change Interrupt" Vector.
|
||||
|
||||
**SoftwareSerial** monopolizes the Pin Change Interrupt Vector and do not allow sharing.
|
||||
|
||||
With **SoftSerial**, it's possible. Don't forget to #include **TinyPinChange** in your sketch!
|
||||
|
||||
Additionally, for small devices such as **ATtiny85** (Digispark), it's possible to declare **the same pin for TX and RX**.
|
||||
Data direction is set by using the new **txMode()** and **rxMode()** methods.
|
||||
|
||||
Some examples of use cases:
|
||||
-------------------------
|
||||
* **half-duplex bi-directional serial port on a single wire for debuging purpose**
|
||||
* **half-duplex serial port to interface with Bluetooth module**
|
||||
* **half-duplex serial port to interconnect an arduino with another one**
|
||||
|
||||
Supported Arduinos:
|
||||
------------------
|
||||
* **ATmega368 (UNO)**
|
||||
* **ATmega2560 (MEGA)**
|
||||
* **ATtiny84 (Standalone)**
|
||||
* **ATtiny85 (Standalone or Digispark)**
|
||||
* **ATtiny167 (Digispark pro)**
|
||||
|
||||
Tip and Tricks:
|
||||
--------------
|
||||
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
|
||||
|
||||
API/methods:
|
||||
-----------
|
||||
* The **SoftSerial** library uses the same API as the regular **SoftwareSerial** library:
|
||||
* begin()
|
||||
* end()
|
||||
* available()
|
||||
* read()
|
||||
* listen()
|
||||
* isListening()
|
||||
* overflow()
|
||||
* flush()
|
||||
|
||||
* Two additional methods are used to manage the serial port on a single pin:
|
||||
* txMode()
|
||||
* rxMode()
|
||||
|
||||
Design considerations:
|
||||
---------------------
|
||||
The **SoftSerial** library relies the **TinyPinChange** library **for the RX pin**. This one shall be included in the sketch as well.
|
||||
|
||||
On the arduino MEGA, as all the pins do not support "pin change interrupt", only the following pins are supported **for the RX pin**:
|
||||
|
||||
* 10 -> 15
|
||||
* 50 -> 53
|
||||
* A8 -> A15
|
||||
|
||||
On other devices (ATmega328, ATtiny84, ATtiny85 and ATtiny167), all the pins are usable.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
||||
|
@ -4,8 +4,8 @@ the Pin Change Interrupt Vector.
|
||||
<SoftwareSerial> monopolizes the Pin Change Interrupt Vector and don't allow sharing.
|
||||
With <SoftSerial>, it's possible. Don't forget to #include <TinyPinChange> in your sketch!
|
||||
Additionally, for small devices such as ATtiny85 (Digispark), it's possible to declare the same pin for TX and RX.
|
||||
Data direction is set by using the new txMode() and rxMode methods.
|
||||
RC Navy (2012-2013): http://p.loussouarn.free.fr
|
||||
Data direction is set by using the new txMode() and rxMode() methods.
|
||||
RC Navy (2012-2015): http://p.loussouarn.free.fr
|
||||
|
||||
SoftwareSerial.cpp (formerly NewSoftSerial.cpp) -
|
||||
Multi-instance software serial library for Arduino/Wiring
|
||||
@ -41,8 +41,15 @@ http://arduiniana.org.
|
||||
// oscilloscope or logic analyzer. Beware: it also slightly modifies
|
||||
// the bit times, so don't rely on it too much at high baud rates
|
||||
#define _DEBUG 0
|
||||
#define _DEBUG_PIN1 11
|
||||
#define _DEBUG_PIN2 13
|
||||
#define _DEBUG_PIN1 0//11
|
||||
#define _DEBUG_PIN2 1//13
|
||||
#define FAST_DEBUG //less intrusive
|
||||
#ifndef cbi
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif
|
||||
#ifndef sbi
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif
|
||||
//
|
||||
// Includes
|
||||
//
|
||||
@ -67,46 +74,41 @@ typedef struct _DELAY_TABLE
|
||||
static const DELAY_TABLE PROGMEM table[] =
|
||||
{
|
||||
// baud rxcenter rxintra rxstop tx
|
||||
{ 115200, 1, 17, 17, 12, },
|
||||
{ 57600, 10, 37, 37, 33, },
|
||||
{ 38400, 25, 57, 57, 54, },
|
||||
{ 31250, 31, 70, 70, 68, },
|
||||
{ 28800, 34, 77, 77, 74, },
|
||||
{ 19200, 54, 117, 117, 114, },
|
||||
{ 14400, 74, 156, 156, 153, },
|
||||
{ 9600, 114, 236, 236, 233, },
|
||||
{ 115200, 0, 14, 14, 12, },
|
||||
{ 57600, 5, 34, 34, 32, },
|
||||
{ 38400, 15, 54, 54, 52, },
|
||||
{ 31250, 23, 67, 67, 65, },/* By interpolation */
|
||||
{ 28800, 26, 74, 74, 72, },/* By interpolation */
|
||||
{ 19200, 44, 113, 113, 112, },
|
||||
{ 14400, 74, 156, 153, 153, },/* By interpolation */
|
||||
{ 9600, 114, 234, 234, 233, },
|
||||
{ 4800, 233, 474, 474, 471, },
|
||||
{ 2400, 471, 950, 950, 947, },
|
||||
{ 1200, 947, 1902, 1902, 1899, },
|
||||
{ 2400, 471, 940, 940, 945, },
|
||||
{ 1200, 947, 1902, 1902, 1895, },
|
||||
{ 300, 3804, 7617, 7617, 7614, },
|
||||
};
|
||||
|
||||
const int XMIT_START_ADJUSTMENT = 5;
|
||||
//PL{ table from http://digistump.com/board/index.php/topic,212.msg1214/topicseen.html#msg1214
|
||||
const int XMIT_START_ADJUSTMENT = 0;
|
||||
#elif F_CPU == 16500000
|
||||
|
||||
|
||||
static const DELAY_TABLE PROGMEM table[] =
|
||||
{
|
||||
// baud rxcenter rxintra rxstop tx
|
||||
{ 115200, 1, 18, 18, 12, },
|
||||
{ 57600, 10, 38, 38, 34, },
|
||||
{ 38400, 26, 59, 59, 56, },
|
||||
{ 31250, 32, 72, 72, 70, },
|
||||
{ 28800, 35, 79, 79, 76, },
|
||||
{ 19200, 56, 121, 121, 118, },
|
||||
{ 14400, 76, 161, 161, 158, },
|
||||
{ 9600, 118, 243, 243, 240, },
|
||||
{ 4800, 240, 489, 489, 486, },
|
||||
{ 2400, 486, 980, 980, 977, },
|
||||
{ 1200, 977, 1961, 1961, 1958, },
|
||||
{ 115200, 0, 15, 15, 13, },
|
||||
{ 57600, 3, 35, 35, 33, },
|
||||
{ 38400, 12, 56, 56, 54, },
|
||||
{ 31250, 32, 72, 72, 70, },/* By interpolation */
|
||||
{ 28800, 35, 79, 79, 76, },/* By interpolation */
|
||||
{ 19200, 52, 118, 118, 116, },
|
||||
{ 14400, 76, 161, 161, 158, },/* By interpolation */
|
||||
{ 9600, 118, 241, 241, 238, },
|
||||
{ 4800, 240, 487, 487, 485, },
|
||||
{ 2400, 486, 976, 976, 974, },
|
||||
{ 1200, 977, 1961, 1961, 1956, },
|
||||
{ 600, 1961, 3923, 3923, 3919, },
|
||||
{ 300, 3923, 7855, 7855, 7852, },
|
||||
};
|
||||
|
||||
|
||||
const int XMIT_START_ADJUSTMENT = 5;
|
||||
//PL}
|
||||
const int XMIT_START_ADJUSTMENT = 0;
|
||||
#elif F_CPU == 8000000
|
||||
|
||||
static const DELAY_TABLE table[] PROGMEM =
|
||||
@ -154,7 +156,7 @@ const int XMIT_START_ADJUSTMENT = 6;
|
||||
|
||||
#else
|
||||
|
||||
#error This version of SoftSerial supports only 20, 16 and 8MHz processors
|
||||
#error This version of SoftSerial supports only 20, 16, 16.5 and 8MHz processors
|
||||
|
||||
#endif
|
||||
|
||||
@ -171,9 +173,12 @@ volatile uint8_t SoftSerial::_receive_buffer_head = 0;
|
||||
//
|
||||
// This function generates a brief pulse
|
||||
// for debugging or measuring on an oscilloscope.
|
||||
#if _DEBUG
|
||||
#if defined(FAST_DEBUG)
|
||||
#define DebugPulse(a, bit) sbi(PINB, bit)
|
||||
#else
|
||||
inline void DebugPulse(uint8_t pin, uint8_t count)
|
||||
{
|
||||
#if _DEBUG
|
||||
volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin));
|
||||
|
||||
uint8_t val = *pport;
|
||||
@ -182,9 +187,14 @@ inline void DebugPulse(uint8_t pin, uint8_t count)
|
||||
*pport = val | digitalPinToBitMask(pin);
|
||||
*pport = val;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#else
|
||||
// no debug
|
||||
inline void DebugPulse(uint8_t pin, uint8_t count)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
@ -369,7 +379,6 @@ SoftSerial::SoftSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_log
|
||||
_buffer_overflow(false),
|
||||
_inverse_logic(inverse_logic)
|
||||
{
|
||||
// setTX(transmitPin);
|
||||
setRX(receivePin);
|
||||
setTX(transmitPin);
|
||||
TinyPinChange_RegisterIsr(receivePin, SoftSerial::handle_interrupt);
|
||||
|
@ -3,7 +3,7 @@
|
||||
the Pin Change Interrupt Vector.
|
||||
<SoftwareSerial> monopolizes the Pin Change Interrupt Vector and don't allow sharing.
|
||||
With <SoftSerial>, it's possible. Don't forget to #include <TinyPinChange> in your sketch!
|
||||
RC Navy (2012): http://p.loussouarn.free.fr
|
||||
RC Navy (2012-2015): http://p.loussouarn.free.fr
|
||||
|
||||
SoftwareSerial.h (formerly NewSoftSerial.h) -
|
||||
Multi-instance software serial library for Arduino/Wiring
|
||||
|
@ -43,10 +43,12 @@
|
||||
#define DEBUG_TX_RX_PIN 2 //Adjust here your Tx/Rx debug pin
|
||||
|
||||
SoftSerial MyDbgSerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); //true allows to connect to a regular RS232 without RS232 line driver
|
||||
|
||||
|
||||
#define SERIAL_BAUD_RATE 57600 //Adjust here the serial rate (57600 is the higher supported rate)
|
||||
|
||||
void setup()
|
||||
{
|
||||
MyDbgSerial.begin(38400); //After MyDbgSerial.begin(), the serial port is in rxMode by default
|
||||
MyDbgSerial.begin(SERIAL_BAUD_RATE); //After MyDbgSerial.begin(), the serial port is in rxMode by default
|
||||
MyDbgSerial.txMode(); //Before sending a message, switch to txMode
|
||||
MyDbgSerial.println(F("\nDebug enabled"));
|
||||
MyDbgSerial.rxMode(); //switch to rxMode to be ready to receive some commands
|
||||
|
@ -0,0 +1,60 @@
|
||||
TinyPinChange library
|
||||
=====================
|
||||
|
||||
**TinyPinChange** is an asynchronous (interrupt-driven) library designed to detect event (rising or falling edege) on pins.
|
||||
|
||||
Very often in the arduino world, users complain about conflicts between libraries.
|
||||
|
||||
This **TinyPinChange** library allows to share the "pin change interrupt" vector for several "clients".
|
||||
|
||||
For example, it's possible to use the **SoftRcPulseIn** library whilst using the **SoftSerial** library: both libraries rely on the **TinyPinChange** library.
|
||||
|
||||
Some examples of use cases:
|
||||
-------------------------
|
||||
* **Event detector** (on pins)
|
||||
* **Frequency meter**
|
||||
* **Pulse width meter**
|
||||
* **Tachometer**
|
||||
* **Duty cycle measurement**
|
||||
* **Software serial port** (see **SoftSerial** library which relies on TinyPinChange)
|
||||
|
||||
Supported Arduinos:
|
||||
------------------
|
||||
* **ATmega368 (UNO)**
|
||||
* **ATmega2560 (MEGA)**
|
||||
* **ATtiny84 (Standalone)**
|
||||
* **ATtiny85 (Standalone or Digispark)**
|
||||
* **ATtiny167 (Digispark pro)**
|
||||
|
||||
Tip and Tricks:
|
||||
--------------
|
||||
Develop your project on an arduino UNO or MEGA, and then shrink it by loading the sketch in an ATtiny or Digispark (pro).
|
||||
|
||||
API/methods:
|
||||
-----------
|
||||
* TinyPinChange_Init()
|
||||
* TinyPinChange_RegisterIsr()
|
||||
* TinyPinChange_EnablePin()
|
||||
* TinyPinChange_DisablePin()
|
||||
* TinyPinChange_GetPortEvent()
|
||||
* TinyPinChange_GetCurPortSt()
|
||||
* TinyPinChange_PinToMsk()
|
||||
* TinyPinChange_Edge()
|
||||
* TinyPinChange_RisingEdge
|
||||
* TinyPinChange_FallingEdge
|
||||
|
||||
Design considerations:
|
||||
---------------------
|
||||
On the arduino MEGA, as all the pins do not support "pin change interrupt", only the following pins are supported:
|
||||
|
||||
* 10 -> 15
|
||||
* 50 -> 53
|
||||
* A8 -> A15
|
||||
|
||||
On other devices (ATmega328, ATtiny84, ATtiny85 and ATtiny167), all the pins are usable.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
||||
|
@ -70,7 +70,7 @@ void setup()
|
||||
{
|
||||
TinyPinChange_Init();
|
||||
|
||||
MySerial.begin(38400); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
|
||||
MySerial.begin(57600); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
|
||||
|
||||
VirtualPortNb = TinyPinChange_RegisterIsr(FIRST_INPUT, InterruptFunctionToCall);
|
||||
VirtualPortNb_ = TinyPinChange_RegisterIsr(SECOND_INPUT, InterruptFunctionToCall);
|
||||
@ -118,7 +118,7 @@ uint16_t LocalFirstInputChangeCount;
|
||||
uint16_t LocalSecondInputChangeCount;
|
||||
|
||||
/* Blink the built-in LED */
|
||||
if(millis() - LedStartMs >= 500)
|
||||
if(millis() - LedStartMs >= 500UL)
|
||||
{
|
||||
LedStartMs = millis();
|
||||
digitalWrite(LED_PIN, State);
|
||||
@ -141,7 +141,7 @@ uint16_t LocalSecondInputChangeCount;
|
||||
}
|
||||
|
||||
/* Diplay Transition numbers every second */
|
||||
if((millis() - DisplayStartMs >= 1000) && DisplayEnabled)
|
||||
if((millis() - DisplayStartMs >= 1000UL) && DisplayEnabled)
|
||||
{
|
||||
DisplayStartMs = millis();
|
||||
noInterrupts(); /* Mandatory since counters are 16 bits */
|
||||
|
@ -70,7 +70,7 @@ void setup()
|
||||
{
|
||||
TinyPinChange_Init();
|
||||
|
||||
MySerial.begin(38400); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
|
||||
MySerial.begin(57600); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
|
||||
|
||||
VirtualPortNb = TinyPinChange_RegisterIsr(FIRST_INPUT, InterruptFunctionToCall);
|
||||
VirtualPortNb_ = TinyPinChange_RegisterIsr(SECOND_INPUT, InterruptFunctionToCall);
|
||||
@ -118,7 +118,7 @@ uint16_t LocalFirstInputChangeCount;
|
||||
uint16_t LocalSecondInputChangeCount;
|
||||
|
||||
/* Blink the built-in LED */
|
||||
if(millis() - LedStartMs >= 500)
|
||||
if(millis() - LedStartMs >= 500UL)
|
||||
{
|
||||
LedStartMs = millis();
|
||||
digitalWrite(LED_PIN, State);
|
||||
@ -141,7 +141,7 @@ uint16_t LocalSecondInputChangeCount;
|
||||
}
|
||||
|
||||
/* Diplay Transition numbers every second */
|
||||
if((millis() - DisplayStartMs >= 1000) && DisplayEnabled)
|
||||
if((millis() - DisplayStartMs >= 1000UL) && DisplayEnabled)
|
||||
{
|
||||
DisplayStartMs = millis();
|
||||
noInterrupts(); /* Mandatory since counters are 16 bits */
|
||||
|
@ -70,7 +70,7 @@ void setup()
|
||||
{
|
||||
TinyPinChange_Init();
|
||||
|
||||
MySerial.begin(38400); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
|
||||
MySerial.begin(57600); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
|
||||
|
||||
VirtualPortNb = TinyPinChange_RegisterIsr(FIRST_INPUT, InterruptFunctionToCall);
|
||||
VirtualPortNb_ = TinyPinChange_RegisterIsr(SECOND_INPUT, InterruptFunctionToCall);
|
||||
@ -118,7 +118,7 @@ uint16_t LocalFirstInputChangeCount;
|
||||
uint16_t LocalSecondInputChangeCount;
|
||||
|
||||
/* Blink the built-in LED */
|
||||
if(millis() - LedStartMs >= 500)
|
||||
if(millis() - LedStartMs >= 500UL)
|
||||
{
|
||||
LedStartMs = millis();
|
||||
digitalWrite(LED_PIN, State);
|
||||
@ -141,7 +141,7 @@ uint16_t LocalSecondInputChangeCount;
|
||||
}
|
||||
|
||||
/* Diplay Transition numbers every second */
|
||||
if((millis() - DisplayStartMs >= 1000) && DisplayEnabled)
|
||||
if((millis() - DisplayStartMs >= 1000UL) && DisplayEnabled)
|
||||
{
|
||||
DisplayStartMs = millis();
|
||||
noInterrupts(); /* Mandatory since counters are 16 bits */
|
||||
|
@ -0,0 +1,440 @@
|
||||
/*
|
||||
_____ ____ __ _ ____ _ _ _ _
|
||||
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
|
||||
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
|
||||
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
|
||||
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|
||||
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2013/2014
|
||||
|
||||
http://p.loussouarn.free.fr
|
||||
|
||||
*******************************************************
|
||||
* <TinyPinChange> library Demo *
|
||||
* with display capabilities using *
|
||||
* <SoftSerial> object as single wire serial interface *
|
||||
*******************************************************
|
||||
|
||||
This "Tiny RC Scope" sketch demonstrates how to use <TinyPinChange> and <SoftSerial> libraries.
|
||||
"Tiny RC Scope" acts as a simple real time ASCII oscilloscope for displaying one RC Channel in the serial console.
|
||||
The displayed measurement (in µs) are: pulse width and RC period.
|
||||
|
||||
Trick: By connecting Pin#1 to Pin#0, through a 1K resistor, you can measure the RC Signal provided by the built-in RC generator for testing purpose.
|
||||
Output results are sent to a software serial port. If a real RC signal is connected to Pin0, the trace is displayed in real time in the terminal.
|
||||
|
||||
And the great thing is: using a <SoftSerial> object as a bi-directionnal software serial port (half-duplex) on a single pin to communicate with the outside world!
|
||||
|
||||
To display the sketch results on a PC (in a Terminal):
|
||||
1) Build the "Serial One Wire Debug Cable" and plug it to the regular RS232 port as depicted below.
|
||||
2) Open your favorite Terminal at 57600,n,8,1: HyperTerminal, Teraterm (Windows) or Minicom, GtkTerm (Linux) and CoolTerm (MAC) does the trick.
|
||||
3) You can also use the Serial Monitor of the arduino IDE: Tools->Serial Port and select your RS232 port (may be an USB virtual port), Rate=57600.
|
||||
4) To test "Tiny RC Scope", connect Pin1 to Pin0, and look at the Terminal (57600,n,8,1) connected to Pin2 through a debug cable ()
|
||||
5) The wave form should be displayed in the Terminal,
|
||||
6) Type - to decrease the pulse width (-10us),
|
||||
7) Type + to increase the pulse width (+10us),
|
||||
8) Type m to set the pulse width to its minimum (500us),
|
||||
9) Type n or N to set the pulse width to its Neutral value (1500us),
|
||||
10) Type M to set the pulse width to its Maximum (2500us),
|
||||
11) To measure real RC signals, disconnect the Pin1 from Pin0 and connect a RC receiver output to Pin0,
|
||||
12) The Terminal will display in real time the pulse width of the connected RC channel.
|
||||
13) If the channel is not connected, a flat line is displayed.
|
||||
|
||||
SERIAL ONE WIRE
|
||||
DEBUGGING CABLE
|
||||
_______________ ________________
|
||||
/ \___/\___/ \
|
||||
____
|
||||
.--------. | \
|
||||
| GND |--------------------------------+---o5 \
|
||||
| | 47K | | 9o |
|
||||
| | .--###--' | o4 |
|
||||
| DEBUG | 4.7K | | 8o |
|
||||
| TX_RX |-------------------###--+--|<|------o3 | ---> To regular RS232 SubD 9 pins Male of PC or Serial/USB adapter
|
||||
| PIN | ^ | 1N4148 | 7o |
|
||||
| | | '-----------o2 |
|
||||
'--------' | | 6o |
|
||||
ATtiny85 Single | o1 /
|
||||
(Digispark) I/O |____/
|
||||
(pro) SubD 9 pins
|
||||
Female
|
||||
*/
|
||||
#include <TinyPinChange.h>
|
||||
#include <SoftSerial.h>
|
||||
|
||||
#define RC_CHANNEL_PIN 0 /* RC Channel is connected to pin 0 */
|
||||
#define RC_GEN_PIN 1 /* Pin used as internal RC generator for test purpose */
|
||||
|
||||
#define RC_PINS_MSK (_BV(RC_CHANNEL_PIN) | _BV(RC_GEN_PIN))
|
||||
|
||||
#define DEBUG_TX_RX_PIN 2
|
||||
|
||||
#define DEF_TEST_RC_CH_WIDTH_US 1500 /* This value can be change via the Terminal */
|
||||
#define TEST_RC_PERIOD_US 20000
|
||||
|
||||
#define PULSE_MAX_US 2500
|
||||
#define PULSE_MIN_US 500
|
||||
#define STEP_US 10
|
||||
|
||||
#define ERR_MARGIN_US 150
|
||||
|
||||
#define SERIAL_BAUD_RATE 57600 /* 57600 is the maximum for Receiving commands from the serial port: 1 char -> #200us */
|
||||
SoftSerial MySerial(DEBUG_TX_RX_PIN, DEBUG_TX_RX_PIN, true); /* Tx/Rx on a single Pin !!! (Pin#2) */
|
||||
|
||||
#define ONE_CHAR_TX_TIME_US 200 /* @ 57600 bauds */
|
||||
|
||||
enum {PULSE_SRC_INTERNAL, PULSE_SRC_EXTERNAL};
|
||||
|
||||
typedef struct {
|
||||
uint32_t RisingStartUs;
|
||||
uint32_t RcWidth_us;
|
||||
uint32_t LastRxPulseMs;
|
||||
boolean FallingEdgeFound;
|
||||
}RcChSt_t;
|
||||
|
||||
volatile RcChSt_t Ch; /* volatile, since value are used in ISR and in the loop() */
|
||||
volatile uint32_t RcPeriod_us = TEST_RC_PERIOD_US;
|
||||
uint32_t TestRcWidth_us = DEF_TEST_RC_CH_WIDTH_US;
|
||||
|
||||
/* The different states of the display state machine */
|
||||
enum {DISP_COMPUTE, DISP_FIRST_LINE, DISP_PREP_SEC_LINE, DISP_SECOND_LINE, DISP_PREP_THIRD_LINE, DISP_THIRD_LINE, DISP_WAIT};
|
||||
|
||||
#define LINE_LEN 38
|
||||
|
||||
typedef struct{
|
||||
char Line[LINE_LEN];
|
||||
uint8_t Idx;
|
||||
uint8_t State;
|
||||
uint8_t HighNb;
|
||||
}DispSt_t;
|
||||
|
||||
static DispSt_t Disp;
|
||||
|
||||
volatile uint8_t IntRcSynch = 0;
|
||||
uint8_t VirtualPortIdx;
|
||||
/*
|
||||
RC Signal
|
||||
____ ____
|
||||
_| |____________________________| |_
|
||||
<---->
|
||||
Width_us
|
||||
<-------------------------------->
|
||||
Period_us
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
TinyPinChange_Init();
|
||||
|
||||
MySerial.begin(SERIAL_BAUD_RATE); /* Trick: use a "high" data rate (less time wasted in ISR and for transmitting each character) */
|
||||
|
||||
Disp.State = DISP_COMPUTE;
|
||||
|
||||
VirtualPortIdx = TinyPinChange_RegisterIsr(RC_CHANNEL_PIN, InterruptFunctionToCall); /* As all pins are on the same port, a single ISR is needed */
|
||||
pinMode(RC_CHANNEL_PIN, INPUT);
|
||||
digitalWrite(RC_CHANNEL_PIN, HIGH); /* Enable Pull-up to avoid floating inputs in case of nothing connected to them */
|
||||
TinyPinChange_EnablePin(RC_CHANNEL_PIN);
|
||||
|
||||
Ch.RcWidth_us = 0;
|
||||
Ch.FallingEdgeFound = 0;
|
||||
|
||||
MySerial.txMode();
|
||||
MySerial.println(F("\n -- Tiny RC Scope V1.0 (C) RC Navy 2014 --\n"));
|
||||
MySerial.rxMode(); /* Switch to Rx Mode */
|
||||
|
||||
pinMode(RC_GEN_PIN, OUTPUT);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint32_t RcGeneStartUs = micros();
|
||||
static uint32_t ProcessStartUs = micros();
|
||||
static uint32_t DisplayStartMs = millis();
|
||||
uint32_t ProcessDurationUs;
|
||||
uint32_t HalfRemaingLowUs;
|
||||
char RxChar;
|
||||
|
||||
/* Blink the built-in LED (Built-in RC Signal generator) */
|
||||
if(IsInternalRcSrc())
|
||||
{
|
||||
RcGeneStartUs = micros();
|
||||
digitalWrite(RC_GEN_PIN, HIGH);
|
||||
while(micros() - RcGeneStartUs < TestRcWidth_us);
|
||||
digitalWrite(RC_GEN_PIN, LOW);
|
||||
}
|
||||
/********************/
|
||||
/* Start of process */
|
||||
/********************/
|
||||
ProcessStartUs = micros();
|
||||
DisplayRcMeasurement(5000U);/* Gives 5000 us to display a part of the trace */
|
||||
/* Get command from single wire SoftSerial (to tune the built-in generator) */
|
||||
if(MySerial.available() > 0)
|
||||
{
|
||||
RxChar = MySerial.read();MySerial.txMode();MySerial.println("");MySerial.rxMode(); /* Carriage return after the echo */
|
||||
switch(RxChar)
|
||||
{
|
||||
case '-': /* Decrease Built-in RC Pulse */
|
||||
if((TestRcWidth_us - STEP_US) >= PULSE_MIN_US)
|
||||
{
|
||||
TestRcWidth_us -= STEP_US;
|
||||
}
|
||||
break;
|
||||
|
||||
case '+': /* Increase Built-in RC Pulse */
|
||||
if(TestRcWidth_us + STEP_US <= PULSE_MAX_US)
|
||||
{
|
||||
TestRcWidth_us += STEP_US;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm': /* Set Built-in RC Pulse o min value: 500 */
|
||||
TestRcWidth_us = PULSE_MIN_US;
|
||||
break;
|
||||
|
||||
case 'N': /* Set Built-in RC Pulse to Neutral: 1500 */
|
||||
case 'n':
|
||||
TestRcWidth_us = DEF_TEST_RC_CH_WIDTH_US;
|
||||
break;
|
||||
|
||||
case 'M': /* Set Built-in RC Pulse to Max value: 2500 */
|
||||
TestRcWidth_us = PULSE_MAX_US;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/********************/
|
||||
/* End of process */
|
||||
/********************/
|
||||
ProcessDurationUs = micros() - ProcessStartUs; //Compute how many us took the previous instructions
|
||||
if(IsInternalRcSrc())
|
||||
{
|
||||
HalfRemaingLowUs = TEST_RC_PERIOD_US - (ProcessDurationUs + TestRcWidth_us + 100UL);
|
||||
RcGeneStartUs = micros();
|
||||
while((micros() - RcGeneStartUs) < HalfRemaingLowUs);
|
||||
}
|
||||
}
|
||||
/*
|
||||
RC Signal
|
||||
____ ____
|
||||
_| |____________________________| |_
|
||||
<---->
|
||||
Width_us
|
||||
<-------------------------------->
|
||||
Period_us
|
||||
<-------------------->
|
||||
Display is processed here
|
||||
|
||||
Explanation: the display of the trace is performed just after the falling edge of the RC pulse
|
||||
As the duration between 2 pulses is too short to display the full trace, the trace is displayed part by part.
|
||||
A full trace is composed of around 100 characters:
|
||||
At 57600 bauds, one character takes (1/57600) * 10 = 174 us. As there are some overhead, it is closer than 200us.
|
||||
So, the full trace takes 100 x 200 = 20000 us = 20 ms. It's impossible to display the full trace between 2 consecutive pulses.
|
||||
DisplayRcMeasurement() function is the very tricky part of this sketch: it has as argument an amount of time and exits before
|
||||
it exceeds it. A state machine is used to memorize where the display was arrived.
|
||||
*/
|
||||
uint8_t DisplayRcMeasurement(uint16_t FreetimeUs)
|
||||
{
|
||||
static uint32_t LocalRcWidth_us;
|
||||
static uint32_t LocalRcPeriod_us;
|
||||
static uint32_t StartWaitMs;
|
||||
char *Ptr;
|
||||
|
||||
uint32_t ProcessStart_us;
|
||||
uint32_t Elapsed_us;
|
||||
uint8_t StartIdx, Idx;
|
||||
uint8_t Ret = 0;
|
||||
|
||||
switch(Disp.State)
|
||||
{
|
||||
case DISP_COMPUTE:
|
||||
DispCompute:
|
||||
if(Ch.FallingEdgeFound)
|
||||
{
|
||||
DispComputeNoSignal:
|
||||
ProcessStart_us = micros();
|
||||
Ch.FallingEdgeFound = 0;
|
||||
noInterrupts(); /* Mandatory since RcWidth_us and RcPeriod_us are 32 bits */
|
||||
LocalRcWidth_us = Ch.RcWidth_us;
|
||||
LocalRcPeriod_us = RcPeriod_us;
|
||||
interrupts();
|
||||
|
||||
if(LocalRcWidth_us < (PULSE_MIN_US - ERR_MARGIN_US) || LocalRcWidth_us > (PULSE_MAX_US + ERR_MARGIN_US)) LocalRcWidth_us = 0; /* Out of Range */
|
||||
Disp.HighNb = (LocalRcWidth_us + 50UL) / 100;
|
||||
strcpy_P(Disp.Line, PSTR("Ch(P0)__"));
|
||||
if(LocalRcWidth_us)
|
||||
{
|
||||
Ptr = Disp.Line + 8;
|
||||
for(Idx = 0; Idx < Disp.HighNb; Idx++) *Ptr++='_';*Ptr++='\n';*Ptr=0;
|
||||
}
|
||||
else Disp.Line[6] = 0;
|
||||
Elapsed_us = micros() - ProcessStart_us;
|
||||
FreetimeUs -= (uint16_t)Elapsed_us;
|
||||
Disp.Idx=0;
|
||||
Disp.State = DISP_FIRST_LINE;
|
||||
if(FreetimeUs >= ONE_CHAR_TX_TIME_US)
|
||||
{
|
||||
goto DispFirstLine;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(millis() - StartWaitMs >= 1000UL)
|
||||
{
|
||||
LocalRcWidth_us = 0;
|
||||
goto DispComputeNoSignal;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DISP_PREP_SEC_LINE:
|
||||
DispPrepSecLine:
|
||||
/* Prepare second line */
|
||||
ProcessStart_us = micros();
|
||||
if(LocalRcWidth_us)
|
||||
{
|
||||
strcpy_P(Disp.Line, PSTR("_____/"));
|
||||
for(Idx = 0; Idx < (2 + Disp.HighNb); Idx++) Disp.Line[6 + Idx] = ' ';
|
||||
itoa(LocalRcWidth_us, Disp.Line + 6, 10);StartIdx = 9; if(LocalRcWidth_us >= 1000) StartIdx++;Disp.Line[StartIdx++] = 'u';Disp.Line[StartIdx++] = 's';
|
||||
StartIdx = 6 + 2 + Disp.HighNb;Disp.Line[StartIdx++] = '\\';
|
||||
}
|
||||
else StartIdx = 0;
|
||||
for(Idx = 0; (StartIdx + Idx ) < (LINE_LEN - 2); Idx++) Disp.Line[StartIdx + Idx] = '_';Disp.Line[StartIdx + Idx] = '\n';Disp.Line[++StartIdx + Idx] = 0;
|
||||
Elapsed_us = micros() - ProcessStart_us;
|
||||
FreetimeUs -= (uint16_t)Elapsed_us;
|
||||
Disp.Idx=0;
|
||||
Disp.State = DISP_SECOND_LINE;
|
||||
if(FreetimeUs >= ONE_CHAR_TX_TIME_US)
|
||||
{
|
||||
goto DispSecondLine;
|
||||
}
|
||||
break;
|
||||
|
||||
case DISP_PREP_THIRD_LINE:
|
||||
DispPrepThirdLine:
|
||||
/* Prepare third line */
|
||||
ProcessStart_us = micros();
|
||||
strcpy_P(Disp.Line, PSTR(" RC Period: "));
|
||||
if(LocalRcWidth_us)
|
||||
{
|
||||
itoa(LocalRcPeriod_us, Disp.Line + 20, 10);
|
||||
strcat_P(Disp.Line, PSTR("us"));
|
||||
}
|
||||
else strcat_P(Disp.Line, PSTR("???"));
|
||||
Elapsed_us = micros() - ProcessStart_us;
|
||||
FreetimeUs -= (uint16_t)Elapsed_us;
|
||||
Disp.Idx=0;
|
||||
Disp.State = DISP_THIRD_LINE;
|
||||
if(FreetimeUs >= ONE_CHAR_TX_TIME_US)
|
||||
{
|
||||
goto DispThirdLine;
|
||||
}
|
||||
break;
|
||||
|
||||
case DISP_FIRST_LINE:
|
||||
case DISP_SECOND_LINE:
|
||||
case DISP_THIRD_LINE:
|
||||
DispFirstLine:
|
||||
DispSecondLine:
|
||||
DispThirdLine:
|
||||
ProcessStart_us = micros();
|
||||
MySerial.txMode();
|
||||
while(1)
|
||||
{
|
||||
if(Disp.Line[Disp.Idx])
|
||||
{
|
||||
MySerial.print(Disp.Line[Disp.Idx++]);
|
||||
if (micros() - ProcessStart_us >= (FreetimeUs - ONE_CHAR_TX_TIME_US))
|
||||
{
|
||||
MySerial.rxMode();
|
||||
break; /* exit while(1) and stay in the current state */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(Disp.State)
|
||||
{
|
||||
case DISP_FIRST_LINE:
|
||||
/* First line is fully displayed */
|
||||
Disp.State = DISP_PREP_SEC_LINE;
|
||||
if(FreetimeUs - Elapsed_us >= 200)
|
||||
{
|
||||
FreetimeUs -= (uint16_t)Elapsed_us;
|
||||
goto DispPrepSecLine;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not enough time: just change state */
|
||||
MySerial.rxMode();
|
||||
}
|
||||
break;
|
||||
|
||||
case DISP_SECOND_LINE:
|
||||
/* Second line is fully displayed */
|
||||
Disp.State = DISP_PREP_THIRD_LINE;
|
||||
if(FreetimeUs - Elapsed_us >= 200)
|
||||
{
|
||||
FreetimeUs -= (uint16_t)Elapsed_us;
|
||||
goto DispPrepThirdLine;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not enough time: just change state */
|
||||
MySerial.rxMode();
|
||||
}
|
||||
break;
|
||||
|
||||
case DISP_THIRD_LINE:
|
||||
/* Third line is fully displayed */
|
||||
MySerial.print('\n');
|
||||
StartWaitMs = millis();
|
||||
Disp.State = DISP_WAIT;
|
||||
MySerial.rxMode();
|
||||
break;
|
||||
}
|
||||
break; /* exit while(1) */
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DISP_WAIT:
|
||||
if(millis() - StartWaitMs >= 500UL) Disp.State = DISP_COMPUTE; /* Give some time to enter commands via the terminal (in internal source mode) */
|
||||
else Ch.FallingEdgeFound = false;
|
||||
break;
|
||||
}
|
||||
return(Ret);
|
||||
}
|
||||
|
||||
/* The following function checks if the received signal is the image of the one of the built-in RC generator */
|
||||
uint8_t IsInternalRcSrc()
|
||||
{
|
||||
uint8_t Ret;
|
||||
static uint32_t SampleStartMs = millis();
|
||||
if(millis() - Ch.LastRxPulseMs >= 300UL) IntRcSynch = 100; /* Kick off Internal RC generator */
|
||||
Ret = (IntRcSynch >= 100);
|
||||
if(millis() - SampleStartMs >= 10UL)
|
||||
{
|
||||
SampleStartMs = millis();
|
||||
IntRcSynch = 99;
|
||||
}
|
||||
return(Ret);
|
||||
}
|
||||
|
||||
/* Function called in interruption in case of change on RC pins: pulse width and RC period measurement */
|
||||
void InterruptFunctionToCall(void)
|
||||
{
|
||||
if(TinyPinChange_RisingEdge(VirtualPortIdx, RC_CHANNEL_PIN)) /* Check for RC Channel rising edge */
|
||||
{
|
||||
RcPeriod_us = micros() - Ch.RisingStartUs;
|
||||
Ch.RisingStartUs = micros();
|
||||
}
|
||||
else
|
||||
{
|
||||
Ch.RcWidth_us = micros() - Ch.RisingStartUs;
|
||||
Ch.FallingEdgeFound = true;
|
||||
Ch.LastRxPulseMs = millis();
|
||||
if(!(PINB & RC_PINS_MSK)) /* Check if RC_CHANNEL_PIN and RC_GEN_PIN are both to 0 */
|
||||
{
|
||||
if(IntRcSynch < 100) IntRcSynch++; /* if IntRcSynch reaches 100, it means the RC source is internal (synchronized) */
|
||||
}else IntRcSynch = 0; /* Not synchronized */
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
TinySoftPwm library
|
||||
===================
|
||||
|
||||
**TinySoftPwm** is a library designed to generate PWM signals by software.
|
||||
|
||||
Some examples of use cases:
|
||||
-------------------------
|
||||
* **RGB strip LED Controller**
|
||||
* **DC Motor controller**
|
||||
* **Digital to Analog converter**
|
||||
|
||||
Supported Arduinos:
|
||||
------------------
|
||||
* **ATtiny85 (Standalone or Digispark)** (up to 6 software PWM supported)
|
||||
* **ATtiny167 (Digispark pro)** (up to 13 software PWM supported)
|
||||
|
||||
API/methods:
|
||||
-----------
|
||||
* TinySoftPwm_begin()
|
||||
* TinySoftPwm_analogWrite()
|
||||
* TinySoftPwm_process()
|
||||
|
||||
|
||||
Design considerations:
|
||||
---------------------
|
||||
In order to reduce **program** and **RAM** memories, PWM pins shall be declared in the **TinySoftPwm.h** file. All the required amount of **program** and **RAM** memories are allocated at compilation time.
|
||||
|
||||
The **TinySoftPwm_process()** method shall be called periodically:
|
||||
|
||||
* using micros() in the loop(): in this case, asynchronous programmation shall be used: no call to blocking functions such as delay() is permitted.
|
||||
* or better using periodic interruption.
|
||||
|
||||
In order to reduce the memory footprint (programm and RAM), try to use the PWM on pins which are part of the same port: PORTA or PORTB.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
If you have some ideas of enhancement, please contact me by clicking on: [RC Navy](http://p.loussouarn.free.fr/contact.html).
|
||||
|
@ -2,46 +2,111 @@
|
||||
// Only resources RAM/Program Memory of used pins are declared in the code at compilation time.
|
||||
// based largely on Atmel's AVR136: Low-Jitter Multi-Channel Software PWM Application Note:
|
||||
// http://www.atmel.com/dyn/resources/prod_documents/doc8020.pdf
|
||||
// RC Navy 2013
|
||||
// RC Navy 2013-2015
|
||||
// http://p.loussouarn.free.fr
|
||||
// 11/01/2015: Multi port support added for ATtiny167
|
||||
|
||||
#include <TinySoftPwm.h>
|
||||
|
||||
#define TINY_SOFT_PWM_PORT PORTB
|
||||
#define TINY_SOFT_PWM_DDR DDRB
|
||||
|
||||
#define TINY_SOFT_PWM_CLEAR_PIN(RamIdx) (PortPwmTo1 &= GET_INV_PIN_MSK(RamIdx))
|
||||
#if (TINY_SOFT_PWM_CH_MAX == 0)
|
||||
#error At least one PWM pin shall be declared in TinySoftPwm.h
|
||||
#endif
|
||||
|
||||
#define TINY_SOFT_PWM_DECLARE_PIN(Px) TINY_SOFT_PWM_DDR |= (1<<(Px)); PortPwmMask |= (1<<(Px))
|
||||
#if defined(TINY_SOFT_PWM_DDR1) && defined(TINY_SOFT_PWM_DDR0)
|
||||
#define TINY_SOFT_PWM_DECLARE_PIN(Pin) do{ \
|
||||
if(digitalPinToPortIdx(Pin)) \
|
||||
{ \
|
||||
TINY_SOFT_PWM_DDR1 |= (1 << digitalPinToPortBit(Pin)); \
|
||||
Port1_PwmMask |= (1 << digitalPinToPortBit(Pin)); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
TINY_SOFT_PWM_DDR0 |= (1 << digitalPinToPortBit(Pin)); \
|
||||
Port0_PwmMask |= (1 << digitalPinToPortBit(Pin)); \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
#define GET_INV_PIN_MSK(RamIdx) ((uint8_t)pgm_read_byte(&RamIdxToInvPinMsk[(RamIdx)]))
|
||||
#define TINY_SOFT_PWM_CLEAR_PIN(RamIdx) GET_PWM_PIN_PORT(RamIdx) \
|
||||
? (Port1_PwmTo1 &= GET_PWM_INV_MSK(RamIdx)) \
|
||||
: (Port0_PwmTo1 &= GET_PWM_INV_MSK(RamIdx))
|
||||
#else
|
||||
#if defined(TINY_SOFT_PWM_DDR1)
|
||||
#define TINY_SOFT_PWM_DECLARE_PIN(Pin) TINY_SOFT_PWM_DDR1 |= (1 << digitalPinToPortBit(Pin)); Port1_PwmMask |= (1 << digitalPinToPortBit(Pin))
|
||||
#define TINY_SOFT_PWM_CLEAR_PIN(RamIdx) Port1_PwmTo1 &= GET_PWM_INV_MSK(RamIdx)
|
||||
#else
|
||||
#define TINY_SOFT_PWM_DECLARE_PIN(Pin) TINY_SOFT_PWM_DDR0 |= (1 << digitalPinToPortBit(Pin)); Port0_PwmMask |= (1 << digitalPinToPortBit(Pin))
|
||||
#define TINY_SOFT_PWM_CLEAR_PIN(RamIdx) Port0_PwmTo1 &= GET_PWM_INV_MSK(RamIdx)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uint8_t RamIdxToInvPinMsk[] PROGMEM ={
|
||||
#if (TINY_SOFT_PWM_USES_P0 == 1)
|
||||
~(1<<0),
|
||||
#define GET_PWM_PIN_ID(RamIdx) ((uint8_t)pgm_read_byte(&PwmPin[(RamIdx)].Id))
|
||||
#define GET_PWM_PIN_PORT(RamIdx) ((uint8_t)pgm_read_byte(&PwmPin[(RamIdx)].Port))
|
||||
#define GET_PWM_INV_MSK(RamIdx) ((uint8_t)pgm_read_byte(&PwmPin[(RamIdx)].InvMsk))
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t Id;
|
||||
uint8_t Port;
|
||||
uint8_t InvMsk;
|
||||
}SoftPwmPinSt_t;
|
||||
|
||||
const SoftPwmPinSt_t PwmPin[] PROGMEM ={
|
||||
#if (TINY_SOFT_PWM_USES_PIN0 == 1)
|
||||
{0, digitalPinToPortIdx(0), ~(1 << digitalPinToPortBit(0))},
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_P1 == 1)
|
||||
~(1<<1),
|
||||
#if (TINY_SOFT_PWM_USES_PIN1 == 1)
|
||||
{1, digitalPinToPortIdx(1), ~(1 << digitalPinToPortBit(1))},
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_P2 == 1)
|
||||
~(1<<2),
|
||||
#if (TINY_SOFT_PWM_USES_PIN2 == 1)
|
||||
{2, digitalPinToPortIdx(2), ~(1 << digitalPinToPortBit(2))},
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_P3 == 1)
|
||||
~(1<<3),
|
||||
#if (TINY_SOFT_PWM_USES_PIN3 == 1)
|
||||
{3, digitalPinToPortIdx(3), ~(1 << digitalPinToPortBit(3))},
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_P4 == 1)
|
||||
~(1<<4),
|
||||
#if (TINY_SOFT_PWM_USES_PIN4 == 1)
|
||||
{4, digitalPinToPortIdx(4), ~(1 << digitalPinToPortBit(4))},
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_P5 == 1)
|
||||
~(1<<5),
|
||||
#if (TINY_SOFT_PWM_USES_PIN5 == 1)
|
||||
{5, digitalPinToPortIdx(5), ~(1 << digitalPinToPortBit(5))},
|
||||
#endif
|
||||
#if defined (__AVR_ATtiny167__)
|
||||
#if (TINY_SOFT_PWM_USES_PIN6 == 1)
|
||||
{6, digitalPinToPortIdx(6), ~(1 << digitalPinToPortBit(6))},
|
||||
#endif
|
||||
};
|
||||
#if (TINY_SOFT_PWM_USES_PIN7 == 1)
|
||||
{7, digitalPinToPortIdx(7), ~(1 << digitalPinToPortBit(7))},
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN8 == 1)
|
||||
{8, digitalPinToPortIdx(8), ~(1 << digitalPinToPortBit(8))},
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN9 == 1)
|
||||
{9, digitalPinToPortIdx(9), ~(1 << digitalPinToPortBit(9))},
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN10 == 1)
|
||||
{10, digitalPinToPortIdx(10), ~(1 << digitalPinToPortBit(10))},
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN11 == 1)
|
||||
{11, digitalPinToPortIdx(11), ~(1 << digitalPinToPortBit(11))},
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN12 == 1)
|
||||
{12, digitalPinToPortIdx(12), ~(1 << digitalPinToPortBit(12))},
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
static uint8_t Compare[TINY_SOFT_PWM_CH_MAX];
|
||||
volatile uint8_t PwmOrder[TINY_SOFT_PWM_CH_MAX];
|
||||
static uint8_t PortPwmMask=0;
|
||||
volatile uint8_t PortPwmTo1=0x00;
|
||||
volatile uint8_t PortPwmTo0=0xFF;
|
||||
static uint8_t _TickMax=255;
|
||||
#ifdef TINY_SOFT_PWM_PORT0
|
||||
static uint8_t Port0_PwmMask = 0;
|
||||
volatile uint8_t Port0_PwmTo1 = 0x00;
|
||||
volatile uint8_t Port0_PwmTo0 = 0xFF;
|
||||
#endif
|
||||
#ifdef TINY_SOFT_PWM_PORT1
|
||||
static uint8_t Port1_PwmMask = 0;
|
||||
volatile uint8_t Port1_PwmTo1 = 0x00;
|
||||
volatile uint8_t Port1_PwmTo0 = 0xFF;
|
||||
#endif
|
||||
static uint8_t _TickMax = 255;
|
||||
|
||||
static uint8_t PwmToPwmMax(uint8_t Pwm);
|
||||
|
||||
@ -50,44 +115,70 @@ void TinySoftPwm_begin(uint8_t TickMax, uint8_t PwmInit)
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
// set the direction of the used ports and update PortPwmMask
|
||||
#if (TINY_SOFT_PWM_USES_P0 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(PB0);
|
||||
#if (TINY_SOFT_PWM_USES_PIN0 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(0);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_P1 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(PB1);
|
||||
#if (TINY_SOFT_PWM_USES_PIN1 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(1);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_P2 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(PB2);
|
||||
#if (TINY_SOFT_PWM_USES_PIN2 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(2);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_P3 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(PB3);
|
||||
#if (TINY_SOFT_PWM_USES_PIN3 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(3);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_P4 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(PB4);
|
||||
#if (TINY_SOFT_PWM_USES_PIN4 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(4);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_P5 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(PB5);
|
||||
#if (TINY_SOFT_PWM_USES_PIN5 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(5);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN6 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(6);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN7 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(7);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN8 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(8);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN9 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(9);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN10 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(10);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN11 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(11);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_USES_PIN12 == 1)
|
||||
TINY_SOFT_PWM_DECLARE_PIN(12);
|
||||
#endif
|
||||
_TickMax = TickMax;
|
||||
#ifdef TINY_SOFT_PWM_PORT0
|
||||
Port0_PwmTo1 = Port0_PwmMask;
|
||||
#endif
|
||||
#ifdef TINY_SOFT_PWM_PORT1
|
||||
Port1_PwmTo1 = Port1_PwmMask;
|
||||
#endif
|
||||
_TickMax=TickMax;
|
||||
PortPwmTo1=PortPwmMask;
|
||||
// initialise all channels
|
||||
for(uint8_t i=0 ; i<TINY_SOFT_PWM_CH_MAX ; i++)
|
||||
for(uint8_t i = 0; i < TINY_SOFT_PWM_CH_MAX; i++)
|
||||
{
|
||||
Compare[i] = PwmToPwmMax(PwmInit); // set default PWM values
|
||||
Compare[i] = PwmToPwmMax(PwmInit); // set default PWM values
|
||||
PwmOrder[i] = Compare[i]; // set default PWM values
|
||||
}
|
||||
SREG = oldSREG;
|
||||
}
|
||||
|
||||
void TinySoftPwm_analogWrite(uint8_t PinIdx, uint8_t Pwm)
|
||||
void TinySoftPwm_analogWrite(uint8_t Pin, uint8_t Pwm)
|
||||
{
|
||||
uint8_t RamIdx;
|
||||
|
||||
for(RamIdx=0;RamIdx<TINY_SOFT_PWM_CH_MAX;RamIdx++)
|
||||
for(RamIdx = 0; RamIdx < TINY_SOFT_PWM_CH_MAX; RamIdx++)
|
||||
{
|
||||
if(GET_INV_PIN_MSK(RamIdx)==((1<<PinIdx)^0xFF)) break;
|
||||
if(GET_PWM_PIN_ID(RamIdx) == Pin) break;
|
||||
}
|
||||
if(RamIdx<TINY_SOFT_PWM_CH_MAX)
|
||||
if(RamIdx < TINY_SOFT_PWM_CH_MAX)
|
||||
{
|
||||
PwmOrder[RamIdx] = PwmToPwmMax(Pwm);
|
||||
}
|
||||
@ -95,16 +186,26 @@ uint8_t RamIdx;
|
||||
|
||||
static uint8_t PwmToPwmMax(uint8_t Pwm)
|
||||
{
|
||||
return(map(Pwm, 0, 255, 0, _TickMax));
|
||||
uint16_t Pwm16;
|
||||
Pwm16 = map(Pwm, 0, 255, 0, _TickMax);
|
||||
Pwm16 = constrain(Pwm16, 0, _TickMax);
|
||||
return((uint8_t)Pwm16);
|
||||
}
|
||||
|
||||
void TinySoftPwm_process(void)
|
||||
{
|
||||
static uint8_t OvfCount=0xFF;
|
||||
|
||||
PortPwmTo0 = (~PortPwmTo1)^PortPwmMask;
|
||||
TINY_SOFT_PWM_PORT |= PortPwmTo1; // update ONLY used outputs to 1 without disturbing the others
|
||||
TINY_SOFT_PWM_PORT &= PortPwmTo0; // update ONLY used outputs to 0 without disturbing the others
|
||||
#ifdef TINY_SOFT_PWM_PORT0
|
||||
Port0_PwmTo0 = (~Port0_PwmTo1) ^ Port0_PwmMask;
|
||||
TINY_SOFT_PWM_PORT0 |= Port0_PwmTo1; // update ONLY used outputs to 1 without disturbing the others
|
||||
TINY_SOFT_PWM_PORT0 &= Port0_PwmTo0; // update ONLY used outputs to 0 without disturbing the others
|
||||
#endif
|
||||
#ifdef TINY_SOFT_PWM_PORT1
|
||||
Port1_PwmTo0 = (~Port1_PwmTo1) ^ Port1_PwmMask;
|
||||
TINY_SOFT_PWM_PORT1 |= Port1_PwmTo1; // update ONLY used outputs to 1 without disturbing the others
|
||||
TINY_SOFT_PWM_PORT1 &= Port1_PwmTo0; // update ONLY used outputs to 0 without disturbing the others
|
||||
#endif
|
||||
if(++OvfCount == _TickMax)
|
||||
{ // increment modulo 256 counter and update
|
||||
// the compare values only when counter = 0.
|
||||
@ -127,7 +228,33 @@ static uint8_t OvfCount=0xFF;
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 6)
|
||||
Compare[5] = PwmOrder[5];
|
||||
#endif
|
||||
PortPwmTo1 = PortPwmMask; // set all port used pins high
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 7)
|
||||
Compare[6] = PwmOrder[6]; // verbose code for speed
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 8)
|
||||
Compare[7] = PwmOrder[7];
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 9)
|
||||
Compare[8] = PwmOrder[8];
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 10)
|
||||
Compare[9] = PwmOrder[9];
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 11)
|
||||
Compare[10] = PwmOrder[10];
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 12)
|
||||
Compare[11] = PwmOrder[11];
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 13)
|
||||
Compare[12] = PwmOrder[12];
|
||||
#endif
|
||||
#ifdef TINY_SOFT_PWM_PORT0
|
||||
Port0_PwmTo1 = Port0_PwmMask; // set all port used pins high
|
||||
#endif
|
||||
#ifdef TINY_SOFT_PWM_PORT1
|
||||
Port1_PwmTo1 = Port1_PwmMask; // set all port used pins high
|
||||
#endif
|
||||
}
|
||||
// clear port pin on compare match (executed on next interrupt)
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 1)
|
||||
@ -148,4 +275,25 @@ static uint8_t OvfCount=0xFF;
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 6)
|
||||
if(Compare[5] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(5);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 7)
|
||||
if(Compare[6] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(6);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 8)
|
||||
if(Compare[7] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(7);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 9)
|
||||
if(Compare[8] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(8);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 10)
|
||||
if(Compare[9] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(9);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 11)
|
||||
if(Compare[10] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(10);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 12)
|
||||
if(Compare[11] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(11);
|
||||
#endif
|
||||
#if (TINY_SOFT_PWM_CH_MAX >= 13)
|
||||
if(Compare[12] == OvfCount) TINY_SOFT_PWM_CLEAR_PIN(12);
|
||||
#endif
|
||||
}
|
||||
|
@ -5,8 +5,9 @@
|
||||
// Only resources RAM/Program Memory of used pins are declared in the code at compilation time.
|
||||
// based largely on Atmel's AVR136: Low-Jitter Multi-Channel Software PWM Application Note:
|
||||
// http://www.atmel.com/dyn/resources/prod_documents/doc8020.pdf
|
||||
// RC Navy 2013
|
||||
// RC Navy 2013-2015
|
||||
// http://p.loussouarn.free.fr
|
||||
// 11/01/2015: Automated multi port support (at compilation time) added for ATtiny167
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
@ -20,67 +21,172 @@
|
||||
/* Define here the PIN to use with Tiny Soft PWM */
|
||||
/* Unused Pin(s) SHALL be commented */
|
||||
/*************************************************/
|
||||
#define TINY_SOFT_PWM_USES_P0
|
||||
#define TINY_SOFT_PWM_USES_P1
|
||||
#define TINY_SOFT_PWM_USES_P2
|
||||
//#define TINY_SOFT_PWM_USES_P3 /* /!\ used for USB on DigiSpark: do not use it for PWM if DigiUSB is also used /!\ */
|
||||
//#define TINY_SOFT_PWM_USES_P4 /* /!\ used for USB on DigiSpark: do not use it for PWM if DigiUSB is also used /!\ */
|
||||
//#define TINY_SOFT_PWM_USES_P5
|
||||
|
||||
|
||||
|
||||
#define TINY_SOFT_PWM_USES_PIN0
|
||||
#define TINY_SOFT_PWM_USES_PIN1
|
||||
#define TINY_SOFT_PWM_USES_PIN2
|
||||
#define TINY_SOFT_PWM_USES_PIN3 /* /!\ used for USB on DigiSpark (pro): do not use it for PWM if DigiUSB or SerialCDC are also used /!\ */
|
||||
#define TINY_SOFT_PWM_USES_PIN4 /* /!\ used for USB on DigiSpark (pro): do not use it for PWM if DigiUSB or SerialCDC are also used /!\ */
|
||||
#define TINY_SOFT_PWM_USES_PIN5
|
||||
#define TINY_SOFT_PWM_USES_PIN6
|
||||
#define TINY_SOFT_PWM_USES_PIN7
|
||||
#define TINY_SOFT_PWM_USES_PIN8
|
||||
#define TINY_SOFT_PWM_USES_PIN9
|
||||
#define TINY_SOFT_PWM_USES_PIN10
|
||||
#define TINY_SOFT_PWM_USES_PIN11
|
||||
#define TINY_SOFT_PWM_USES_PIN12
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/* Do NOT modify below: it's used to optimize RAM and Program size */
|
||||
/*******************************************************************/
|
||||
#ifdef TINY_SOFT_PWM_USES_P0
|
||||
#undef TINY_SOFT_PWM_USES_P0
|
||||
#define TINY_SOFT_PWM_USES_P0 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_P0 0
|
||||
#if defined (__AVR_ATtiny85__)
|
||||
#undef TINY_SOFT_PWM_USES_PIN6
|
||||
#undef TINY_SOFT_PWM_USES_PIN7
|
||||
#undef TINY_SOFT_PWM_USES_PIN8
|
||||
#undef TINY_SOFT_PWM_USES_PIN9
|
||||
#undef TINY_SOFT_PWM_USES_PIN10
|
||||
#undef TINY_SOFT_PWM_USES_PIN11
|
||||
#undef TINY_SOFT_PWM_USES_PIN12
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_P1
|
||||
#undef TINY_SOFT_PWM_USES_P1
|
||||
#define TINY_SOFT_PWM_USES_P1 1
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN0
|
||||
#undef TINY_SOFT_PWM_USES_PIN0
|
||||
#define TINY_SOFT_PWM_USES_PIN0 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_P1 0
|
||||
#define TINY_SOFT_PWM_USES_PIN0 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_P2
|
||||
#undef TINY_SOFT_PWM_USES_P2
|
||||
#define TINY_SOFT_PWM_USES_P2 1
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN1
|
||||
#undef TINY_SOFT_PWM_USES_PIN1
|
||||
#define TINY_SOFT_PWM_USES_PIN1 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_P2 0
|
||||
#define TINY_SOFT_PWM_USES_PIN1 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_P3
|
||||
#undef TINY_SOFT_PWM_USES_P3
|
||||
#define TINY_SOFT_PWM_USES_P3 1
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN2
|
||||
#undef TINY_SOFT_PWM_USES_PIN2
|
||||
#define TINY_SOFT_PWM_USES_PIN2 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_P3 0
|
||||
#define TINY_SOFT_PWM_USES_PIN2 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_P4
|
||||
#undef TINY_SOFT_PWM_USES_P4
|
||||
#define TINY_SOFT_PWM_USES_P4 1
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN3
|
||||
#undef TINY_SOFT_PWM_USES_PIN3
|
||||
#define TINY_SOFT_PWM_USES_PIN3 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_P4 0
|
||||
#define TINY_SOFT_PWM_USES_PIN3 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_P5
|
||||
#undef TINY_SOFT_PWM_USES_P5
|
||||
#define TINY_SOFT_PWM_USES_P5 1
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN4
|
||||
#undef TINY_SOFT_PWM_USES_PIN4
|
||||
#define TINY_SOFT_PWM_USES_PIN4 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_P5 0
|
||||
#define TINY_SOFT_PWM_USES_PIN4 0
|
||||
#endif
|
||||
|
||||
#define TINY_SOFT_PWM_CH_MAX (TINY_SOFT_PWM_USES_P0 + TINY_SOFT_PWM_USES_P1 + TINY_SOFT_PWM_USES_P2 + TINY_SOFT_PWM_USES_P3 + TINY_SOFT_PWM_USES_P4 + TINY_SOFT_PWM_USES_P5)
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN5
|
||||
#undef TINY_SOFT_PWM_USES_PIN5
|
||||
#define TINY_SOFT_PWM_USES_PIN5 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_PIN5 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN6
|
||||
#undef TINY_SOFT_PWM_USES_PIN6
|
||||
#define TINY_SOFT_PWM_USES_PIN6 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_PIN6 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN7
|
||||
#undef TINY_SOFT_PWM_USES_PIN7
|
||||
#define TINY_SOFT_PWM_USES_PIN7 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_PIN7 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN8
|
||||
#undef TINY_SOFT_PWM_USES_PIN8
|
||||
#define TINY_SOFT_PWM_USES_PIN8 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_PIN8 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN9
|
||||
#undef TINY_SOFT_PWM_USES_PIN9
|
||||
#define TINY_SOFT_PWM_USES_PIN9 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_PIN9 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN10
|
||||
#undef TINY_SOFT_PWM_USES_PIN10
|
||||
#define TINY_SOFT_PWM_USES_PIN10 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_PIN10 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN11
|
||||
#undef TINY_SOFT_PWM_USES_PIN11
|
||||
#define TINY_SOFT_PWM_USES_PIN11 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_PIN11 0
|
||||
#endif
|
||||
|
||||
#ifdef TINY_SOFT_PWM_USES_PIN12
|
||||
#undef TINY_SOFT_PWM_USES_PIN12
|
||||
#define TINY_SOFT_PWM_USES_PIN12 1
|
||||
#else
|
||||
#define TINY_SOFT_PWM_USES_PIN12 0
|
||||
#endif
|
||||
|
||||
|
||||
#define TINY_SOFT_PWM_CH_MAX (TINY_SOFT_PWM_USES_PIN0 + TINY_SOFT_PWM_USES_PIN1 + TINY_SOFT_PWM_USES_PIN2 + \
|
||||
TINY_SOFT_PWM_USES_PIN3 + TINY_SOFT_PWM_USES_PIN4 + TINY_SOFT_PWM_USES_PIN5 + \
|
||||
TINY_SOFT_PWM_USES_PIN6 + TINY_SOFT_PWM_USES_PIN7 + TINY_SOFT_PWM_USES_PIN8 + \
|
||||
TINY_SOFT_PWM_USES_PIN9 + TINY_SOFT_PWM_USES_PIN10+ TINY_SOFT_PWM_USES_PIN11+ \
|
||||
TINY_SOFT_PWM_USES_PIN12)
|
||||
|
||||
|
||||
#if defined (__AVR_ATtiny85__)
|
||||
#define TINY_SOFT_PWM_USES_PORT0 0
|
||||
#define TINY_SOFT_PWM_USES_PORT1 1
|
||||
#ifndef digitalPinToPortIdx
|
||||
#define digitalPinToPortIdx(p) 1
|
||||
#endif
|
||||
#else
|
||||
#if defined (__AVR_ATtiny167__)
|
||||
#define TINY_SOFT_PWM_USES_PORT0 (TINY_SOFT_PWM_USES_PIN5 || TINY_SOFT_PWM_USES_PIN6 || TINY_SOFT_PWM_USES_PIN7 || \
|
||||
TINY_SOFT_PWM_USES_PIN8 || TINY_SOFT_PWM_USES_PIN9 || TINY_SOFT_PWM_USES_PIN10 || \
|
||||
TINY_SOFT_PWM_USES_PIN11 || TINY_SOFT_PWM_USES_PIN12)
|
||||
#define TINY_SOFT_PWM_USES_PORT1 (TINY_SOFT_PWM_USES_PIN0 || TINY_SOFT_PWM_USES_PIN1 || TINY_SOFT_PWM_USES_PIN2 || \
|
||||
TINY_SOFT_PWM_USES_PIN3 || TINY_SOFT_PWM_USES_PIN4)
|
||||
|
||||
#ifndef digitalPinToPortIdx
|
||||
#define digitalPinToPortIdx(p) (((p) >= 5 && (p) <= 12) ? (0) : (1))
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (TINY_SOFT_PWM_USES_PORT0 == 1)
|
||||
#undef TINY_SOFT_PWM_USES_PORT0
|
||||
#define TINY_SOFT_PWM_PORT0 PORTA
|
||||
#define TINY_SOFT_PWM_DDR0 DDRA
|
||||
#endif
|
||||
|
||||
#if (TINY_SOFT_PWM_USES_PORT1 == 1)
|
||||
#undef TINY_SOFT_PWM_USES_PORT1
|
||||
#define TINY_SOFT_PWM_PORT1 PORTB
|
||||
#define TINY_SOFT_PWM_DDR1 DDRB
|
||||
#endif
|
||||
|
||||
#ifndef digitalPinToPortBit
|
||||
#define digitalPinToPortBit(p) digitalPinToPCMSKbit(p)
|
||||
#endif
|
||||
|
||||
/* Public Function Prototypes */
|
||||
void TinySoftPwm_begin(uint8_t TickMax, uint8_t PwmInit);
|
||||
void TinySoftPwm_analogWrite(uint8_t PinIdx, uint8_t Pwm);
|
||||
void TinySoftPwm_analogWrite(uint8_t Pin, uint8_t Pwm);
|
||||
void TinySoftPwm_process(void);
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,75 @@
|
||||
#include <TinySoftPwm.h>
|
||||
|
||||
/*
|
||||
_____ ____ __ _ ____ _ _ _ _
|
||||
| __ \ / __ \ | \ | | / __ \ | | | | | | | |
|
||||
| |__| | | / \_| | . \ | | / / \ \ | | | | \ \ / /
|
||||
| _ / | | _ | |\ \| | | |__| | | | | | \ ' /
|
||||
| | \ \ | \__/ | | | \ ' | | __ | \ \/ / | |
|
||||
|_| \_\ \____/ |_| \__| |_| |_| \__/ |_| 2015
|
||||
|
||||
http://p.loussouarn.free.fr
|
||||
|
||||
****************************************
|
||||
* <TinySoftPwm> library Demo *
|
||||
****************************************
|
||||
|
||||
This sketch generates simultaneously PWM signals on 13 pins (Pin 0 to pin 12 of the Digispark pro).
|
||||
It also increases the luminosity of the built-in LED of the Digispark whilst the duty cycle remains constant for all other pins.
|
||||
When the luminosity reaches its maximum, the luminosity decreases.
|
||||
When the luminosity reaches its minimum, the luminosity increases, and so on...
|
||||
|
||||
Note:
|
||||
====
|
||||
Declare the Pin(s) used in "librarie/TinySoftPwm/TinySoftPwm.h"
|
||||
In this sketch, #define TINY_SOFT_PWM_USES_PINO to TINY_SOFT_PWM_USES_PIN12 must be enabled (not commented) since it uses the first 13 pins of the DigiSpark pro.
|
||||
|
||||
In this basic example, TinySoftPwm_process() is called periodically using micros(), but it is recommanded to call it from a timer ISR
|
||||
to ensure a better periodicity.
|
||||
|
||||
*/
|
||||
|
||||
#define BUILT_IN_LED_PIN 1 /* Digispark Model A (Rev2) built-in LED pin number (Change it to 2 for Model B) */
|
||||
|
||||
void setup()
|
||||
{
|
||||
TinySoftPwm_begin(255, 0); /* 255 x TinySoftPwm_process() calls before overlap (Frequency tuning), 0 = PWM init for all declared pins */
|
||||
for(uint8_t PinIdx = 0; PinIdx <= 12; PinIdx++)
|
||||
{
|
||||
TinySoftPwm_analogWrite(PinIdx, (PinIdx + 1) * 19); /* Low to high duty cycle for pin 0 to 12 */
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
static uint32_t StartUs = micros();
|
||||
static uint32_t StartMs = millis();
|
||||
static uint8_t Pwm = 0;
|
||||
static int8_t Dir = 1;
|
||||
|
||||
/***********************************************************/
|
||||
/* Call TinySoftPwm_process() with a period of 40 us */
|
||||
/* The PWM frequency = 255 x 40 # 10.2 ms -> F # 100Hz */
|
||||
/* 255 is the first argument passed to TinySoftPwm_begin() */
|
||||
/***********************************************************/
|
||||
if((micros() - StartUs) >= 40)
|
||||
{
|
||||
/* We arrived here every 40 microseconds */
|
||||
StartUs = micros();
|
||||
TinySoftPwm_process(); /* This function shall be called periodically (like here, based on micros(), or in a timer ISR) */
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
/* Increment/decrement PWM on LED Pin with a period of 10 ms */
|
||||
/*************************************************************/
|
||||
if((millis() - StartMs) >= 10)
|
||||
{
|
||||
/* We arrived here every 10 milliseconds */
|
||||
StartMs = millis();
|
||||
Pwm += Dir; /* increment or decrement PWM depending of sign of Dir */
|
||||
TinySoftPwm_analogWrite(BUILT_IN_LED_PIN, Pwm); /* Update built-in LED for Digispark */
|
||||
if(Pwm == 255) Dir = -1; /* if PWM reaches the maximum: change direction */
|
||||
if(Pwm == 0) Dir = +1; /* if PWM reaches the minimum: change direction */
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,105 @@
|
||||
#include <SPI.h>
|
||||
#include "nRF24L01.h"
|
||||
#include "RF24.h"
|
||||
|
||||
//THESE MUST BE SET! CHANGE ADDRESS AS YOU UPLOAD TO EACH NODE!
|
||||
#define TOTAL_NODES 3 //TOTAL NUMBER OF NODES IN MESH
|
||||
#define NODE_ADDRESS 0 //the sero indexed address of this node - nodes must be numbered 0 thru TOTAL_NODES-1 //also note 255 is broadcast address
|
||||
|
||||
//hold the seuqnce numbers to avoid repeating the same messages
|
||||
uint8_t sequence[TOTAL_NODES];
|
||||
|
||||
//setup radio module
|
||||
RF24 radio(9,12);
|
||||
|
||||
//message format - adjust data as needed - the rest is madatory for this mesh to work
|
||||
struct
|
||||
{
|
||||
char toAddress;
|
||||
char fromAddress;
|
||||
char fromSequence;
|
||||
long data;
|
||||
} msg;
|
||||
|
||||
//don't change! read is same for all nodes, write is automatically calculated here
|
||||
const uint64_t writePipe = 0xF0F0F0F00LL + NODE_ADDRESS;
|
||||
const uint64_t readPipe = 0xF0F0F0F0D2LL;
|
||||
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
radio.begin();
|
||||
radio.setDataRate(RF24_250KBPS); //lowest speed = most range
|
||||
radio.setAutoAck(false); //this is a mesh so we don't want ACKs!
|
||||
radio.setRetries(15, 15);
|
||||
radio.setPayloadSize(sizeof(msg));
|
||||
radio.openWritingPipe(writePipe);
|
||||
radio.openReadingPipe(1, readPipe);
|
||||
radio.startListening();
|
||||
}
|
||||
|
||||
long now = 0;
|
||||
|
||||
void loop() {
|
||||
|
||||
|
||||
|
||||
if(readAndRepeat()){ //will repeat messages as needed and return false unless there is packet for this node - CALL FREQUENTLY!
|
||||
//if this does not return false then we have a packet for THIS node!
|
||||
//msg.fromAddress is the node that sent it
|
||||
//msg.data is the data itself
|
||||
//Do something with it!
|
||||
//For example display packets coming to this node on a LCD:
|
||||
/*
|
||||
NOTE: TO USE THIS ADD THE LCD INCLUDES AND SETUP ROUTINE FROM THE DigisparkLCD example
|
||||
lcd.clear();
|
||||
lcd.print("From: ");
|
||||
lcd.println(msg.fromAddress);
|
||||
lcd.print("Value: ");
|
||||
lcd.println(msg.data);
|
||||
*/
|
||||
}
|
||||
|
||||
if(millis() - now > 10000){ //send a packet from this node to the mesh every 10 seconds but wait in a non-blocking way so that we can still run this loop and repeat things
|
||||
now = millis(); //set now to millis so we wait another 10 seconds before sending again
|
||||
//sendToMesh(To_Address,Data_To_Send);
|
||||
//sendToMesh(0, analogRead(A5)); //send to node 0 the analog read value of pin 5 - could also send a temp sensor value, etc ,etc
|
||||
//sendToMesh(255, analogRead(A5)); //send to all nodes (255 is the broadcast address) the analog read value of pin 5
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void sendToMesh(uint8_t toAddress, long data){
|
||||
if(sequence[NODE_ADDRESS]<255)
|
||||
sequence[NODE_ADDRESS]++; //increment sequence count for this device
|
||||
else
|
||||
sequence[NODE_ADDRESS] = 0; //set to zero if last was 255 so we don't overflow - logic for read is built to handle this too
|
||||
|
||||
msg.toAddress = toAddress; //set the address of the destination node
|
||||
msg.fromAddress = NODE_ADDRESS; //set the from as this node - of course
|
||||
msg.fromSequence = sequence[NODE_ADDRESS]; //set it to the sequence number we just implemented which should be greater than any the nodes have received
|
||||
radio.stopListening(); //turn of recv so we can transmit
|
||||
radio.write(&msg, sizeof(msg));
|
||||
radio.startListening(); //turn recv back on
|
||||
}
|
||||
|
||||
bool readAndRepeat(){
|
||||
if(radio.read(&msg, sizeof(msg))){ //if we have incoming data
|
||||
if(msg.fromAddress!=NODE_ADDRESS){ //make sure this node didn't send it
|
||||
if(sequence[msg.fromAddress] < msg.fromSequence || (sequence[msg.fromAddress] == 255 && msg.fromSequence == 0)){ //make sure we haven't already repeated it or received it
|
||||
//increment sequence for that address so we don't repeat it twice from this node or receive it twice
|
||||
sequence[msg.fromAddress] = msg.fromSequence;
|
||||
if(msg.toAddress==NODE_ADDRESS){ //is it for this node? if so return true so we can use it!
|
||||
return true;
|
||||
}
|
||||
//otherwise repeat it - send it back out
|
||||
radio.write(&msg, sizeof(msg));
|
||||
if(msg.toAddress == 255){ //it was a broadcast so return true so we do something with it
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
@ -20,21 +20,12 @@
|
||||
* length should be these two bytes plus the number of bytes to read.
|
||||
****************************************************************************/
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#if defined (__AVR_ATtiny45__) || defined (__AVR_ATtiny85__)
|
||||
#define F_CPU 16500000UL
|
||||
|
||||
#elif defined (__AVR_ATtiny87__) || defined (__AVR_ATtiny167__)
|
||||
#define F_CPU 16000000UL // Sets up the default speed for delay.h
|
||||
#endif
|
||||
|
||||
#include <util/delay.h>
|
||||
#include <avr/io.h>
|
||||
#include "USI_TWI_Master.h"
|
||||
|
||||
unsigned char USI_TWI_Start_Transceiver_With_Data( unsigned char * , unsigned char );
|
||||
unsigned char USI_TWI_Master_Transfer( unsigned char );
|
||||
unsigned char USI_TWI_Master_Stop( void );
|
||||
unsigned char USI_TWI_Master_Start( void );
|
||||
|
||||
union USI_TWI_state
|
||||
@ -255,11 +246,8 @@ unsigned char USI_TWI_Start_Transceiver_With_Data( unsigned char *msg, unsigned
|
||||
USI_TWI_Master_Transfer( tempUSISR_1bit ); // Generate ACK/NACK.
|
||||
}
|
||||
}while( --msgSize) ; // Until all data sent/received.
|
||||
|
||||
if (!USI_TWI_Master_Stop())
|
||||
{
|
||||
return (FALSE); // Send a STOP condition on the TWI bus.
|
||||
}
|
||||
|
||||
// usually a stop condition is sent here, but TinyWireM needs to choose whether or not to send it
|
||||
|
||||
/* Transmission successfully completed*/
|
||||
return (TRUE);
|
||||
|
@ -22,14 +22,6 @@
|
||||
|
||||
// Defines controlling timing limits - SCL <= 100KHz.
|
||||
|
||||
#if defined (__AVR_ATtiny45__) || defined (__AVR_ATtiny85__)
|
||||
#define SYS_CLK 16500.0 // [kHz] Default for ATtiny2313
|
||||
|
||||
#elif defined (__AVR_ATtiny87__) || defined (__AVR_ATtiny167__)
|
||||
#define SYS_CLK 16000.0 // [kHz] Default for ATtiny2313
|
||||
#endif
|
||||
|
||||
|
||||
// For use with _delay_us()
|
||||
#define T2_TWI 5 // >4,7us
|
||||
#define T4_TWI 4 // >4,0us
|
||||
@ -37,7 +29,7 @@
|
||||
// Defines error code generating
|
||||
//#define PARAM_VERIFICATION
|
||||
//#define NOISE_TESTING
|
||||
#define SIGNAL_VERIFY // This should probably be on always.
|
||||
//#define SIGNAL_VERIFY // This should probably be on always.
|
||||
|
||||
/****************************************************************************
|
||||
Bit and byte definitions
|
||||
@ -77,8 +69,8 @@
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATtiny25__) | defined(__AVR_ATtiny45__) | defined(__AVR_ATtiny85__) | \
|
||||
defined(__AVR_AT90Tiny26__) | defined(__AVR_ATtiny26__) | defined(__AVR_ATtiny167__) | \
|
||||
defined(__AVR_ATtiny87__)
|
||||
defined(__AVR_AT90Tiny26__) | defined(__AVR_ATtiny26__) | defined(__AVR_ATtiny87__) | \
|
||||
defined(__AVR_ATtiny167__)
|
||||
#define DDR_USI DDRB
|
||||
#define PORT_USI PORTB
|
||||
#define PIN_USI PINB
|
||||
@ -88,6 +80,16 @@
|
||||
#define PIN_USI_SCL PINB2
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATtiny84__) | defined(__AVR_ATtiny44__)
|
||||
# define DDR_USI DDRA
|
||||
# define PORT_USI PORTA
|
||||
# define PIN_USI PINA
|
||||
# define PORT_USI_SDA PORTA6
|
||||
# define PORT_USI_SCL PORTA4
|
||||
# define PIN_USI_SDA PINA6
|
||||
# define PIN_USI_SCL PINA4
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_AT90Tiny2313__) | defined(__AVR_ATtiny2313__)
|
||||
#define DDR_USI DDRB
|
||||
#define PORT_USI PORTB
|
||||
@ -119,4 +121,5 @@
|
||||
void USI_TWI_Master_Initialise( void );
|
||||
unsigned char USI_TWI_Start_Random_Read( unsigned char * , unsigned char );
|
||||
unsigned char USI_TWI_Start_Read_Write( unsigned char * , unsigned char );
|
||||
unsigned char USI_TWI_Master_Stop( void );
|
||||
unsigned char USI_TWI_Get_State_Info( void );
|
||||
|
@ -1,7 +1,4 @@
|
||||
/*
|
||||
|
||||
This version has been modified by Digistump to be a drop in replacement for Wire
|
||||
|
||||
TinyWireM.cpp - a wrapper class for TWI/I2C Master library for the ATtiny on Arduino
|
||||
1/21/2011 BroHogan - brohoganx10 at gmail dot com
|
||||
|
||||
@ -40,6 +37,9 @@ USI_TWI::USI_TWI(){
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
//int USI_TWI::peek(){}
|
||||
//void USI_TWI::flush(){}
|
||||
|
||||
void USI_TWI::begin(){ // initialize I2C lib
|
||||
USI_TWI_Master_Initialise();
|
||||
}
|
||||
@ -49,23 +49,32 @@ void USI_TWI::beginTransmission(uint8_t slaveAddr){ // setup address & write bit
|
||||
USI_Buf[USI_BufIdx] = (slaveAddr<<TWI_ADR_BITS) | USI_SEND;
|
||||
}
|
||||
|
||||
void USI_TWI::send(uint8_t data){ // buffers up data to send
|
||||
if (USI_BufIdx >= USI_BUF_SIZE) return; // dont blow out the buffer
|
||||
size_t USI_TWI::write(uint8_t data){ // buffers up data to send
|
||||
if (USI_BufIdx >= USI_BUF_SIZE) return 0; // dont blow out the buffer
|
||||
USI_BufIdx++; // inc for next byte in buffer
|
||||
USI_Buf[USI_BufIdx] = data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void USI_TWI::write(uint8_t data){ // buffers up data to send
|
||||
send(data);
|
||||
uint8_t USI_TWI::endTransmission() {
|
||||
endTransmission(1);
|
||||
}
|
||||
|
||||
|
||||
uint8_t USI_TWI::endTransmission(){ // actually sends the buffer
|
||||
uint8_t USI_TWI::endTransmission(uint8_t stop){ // actually sends the buffer
|
||||
bool xferOK = false;
|
||||
uint8_t errorCode = 0;
|
||||
xferOK = USI_TWI_Start_Read_Write(USI_Buf,USI_BufIdx+1); // core func that does the work
|
||||
USI_BufIdx = 0;
|
||||
if (xferOK) return 0;
|
||||
if (xferOK) {
|
||||
if (stop) {
|
||||
errorCode = USI_TWI_Master_Stop();
|
||||
if (errorCode == 0) {
|
||||
errorCode = USI_TWI_Get_State_Info();
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else { // there was an error
|
||||
errorCode = USI_TWI_Get_State_Info(); // this function returns the error number
|
||||
return errorCode;
|
||||
@ -81,26 +90,33 @@ uint8_t USI_TWI::requestFrom(uint8_t slaveAddr, uint8_t numBytes){ // setup for
|
||||
USI_Buf[0] = (slaveAddr<<TWI_ADR_BITS) | USI_RCVE; // setup address & Rcve bit
|
||||
xferOK = USI_TWI_Start_Read_Write(USI_Buf,numBytes); // core func that does the work
|
||||
// USI_Buf now holds the data read
|
||||
if (xferOK) return 0;
|
||||
if (xferOK) {
|
||||
errorCode = USI_TWI_Master_Stop();
|
||||
if (errorCode == 0) {
|
||||
errorCode = USI_TWI_Get_State_Info();
|
||||
return errorCode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else { // there was an error
|
||||
errorCode = USI_TWI_Get_State_Info(); // this function returns the error number
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t USI_TWI::receive(){ // returns the bytes received one at a time
|
||||
int USI_TWI::read(){ // returns the bytes received one at a time
|
||||
USI_LastRead++; // inc first since first uint8_t read is in USI_Buf[1]
|
||||
return USI_Buf[USI_LastRead];
|
||||
}
|
||||
|
||||
uint8_t USI_TWI::read(){ // returns the bytes received one at a time
|
||||
return USI_TWI::receive();
|
||||
}
|
||||
|
||||
uint8_t USI_TWI::available(){ // the bytes available that haven't been read yet
|
||||
int USI_TWI::available(){ // the bytes available that haven't been read yet
|
||||
return USI_BytesAvail - (USI_LastRead);
|
||||
}
|
||||
|
||||
bool USI_TWI::writeAvailable(){ // the bytes available that haven't been written yet
|
||||
if (USI_BufIdx >= USI_BUF_SIZE) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Preinstantiate Objects //////////////////////////////////////////////////////
|
||||
|
||||
|
@ -1,7 +1,4 @@
|
||||
/*
|
||||
|
||||
This version has been modified by Digistump to be a drop in replacement for Wire
|
||||
|
||||
TinyWireM.h - a wrapper(+) class for TWI/I2C Master library for the ATtiny on Arduino
|
||||
1/21/2011 BroHogan - brohoganx10 at gmail dot com
|
||||
|
||||
@ -41,10 +38,12 @@ This version has been modified by Digistump to be a drop in replacement for Wire
|
||||
#define Wire_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Arduino.h"
|
||||
#define USI_SEND 0 // indicates sending to TWI
|
||||
#define USI_RCVE 1 // indicates receiving from TWI
|
||||
#define USI_BUF_SIZE 16 // bytes in message buffer
|
||||
#define USI_BUF_SIZE 18 // bytes in message buffer
|
||||
|
||||
//class USI_TWI : public Stream
|
||||
class USI_TWI
|
||||
{
|
||||
private:
|
||||
@ -54,19 +53,33 @@ class USI_TWI
|
||||
static uint8_t USI_BytesAvail; // number of bytes requested but not read
|
||||
|
||||
public:
|
||||
USI_TWI();
|
||||
void begin();
|
||||
void beginTransmission(uint8_t);
|
||||
void send(uint8_t);
|
||||
void write(uint8_t);
|
||||
USI_TWI();
|
||||
void begin();
|
||||
void beginTransmission(uint8_t);
|
||||
size_t write(uint8_t);
|
||||
inline size_t write(uint8_t* d, uint8_t n) { uint16_t i; for (i = 0; i < n; i++) write(d[i]); return (size_t)n; }
|
||||
inline size_t write(unsigned long n) { return write((uint8_t)n); }
|
||||
inline size_t write(long n) { return write((uint8_t)n); }
|
||||
inline size_t write(unsigned int n) { return write((uint8_t)n); }
|
||||
inline size_t write(int n) { return write((uint8_t)n); }
|
||||
void send(uint8_t b) { write(b); }
|
||||
void send(uint8_t *d, uint8_t n) { write(d, n); }
|
||||
void send(int n) { write((uint8_t)n); }
|
||||
uint8_t endTransmission();
|
||||
uint8_t endTransmission(uint8_t);
|
||||
uint8_t requestFrom(uint8_t, uint8_t);
|
||||
uint8_t receive();
|
||||
uint8_t read();
|
||||
uint8_t available();
|
||||
int read();
|
||||
int available();
|
||||
bool writeAvailable();
|
||||
int peek(void);
|
||||
void flush(void);
|
||||
uint8_t receive(void) {
|
||||
int c = read();
|
||||
if (c < 0) return 0;
|
||||
return c;
|
||||
}
|
||||
};
|
||||
|
||||
extern USI_TWI Wire;
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -209,7 +209,7 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
TIMER0A,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
|
@ -209,7 +209,7 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
TIMER0A,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
|
@ -209,7 +209,7 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
TIMER0A,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
|
Loading…
x
Reference in New Issue
Block a user