/**@file endianness.c
@brief Code to transmit 16-bit ADC samples in big or little-endian order
@author Stephen Friederichs
@date 5/12/13
ADC Channels:
0 - Accelerometer X axis (Vertical)
1 - Accelerometer Y axis (Horizontal)
2 - Accelerometer Z axis (Lateral)
3 - Accelerometer 0G detect (Freefall detect)
The heartbeat LED is on Port D, pin 7
*/
/**@def F_CPU
@brief Clock frequency = 8MHZ - this is set by fuses and registers, not by this define
@note Always define this before including delay.h!
*/
#define F_CPU 8000000
/**@include io.h
@brief Include for AVR I/O register definitions
*/
#include <avr/io.h>
/**@include stdint.h
@brief Include for standard integer definitions (ie, uint8_t, int32_t, etc)
*/
#include <stdint.h>
/**@include delay.h
@brief Include for delay functions such as _delay_ms() and _delay_us()
*/
#include <util/delay.h>
/* Basic bit manipulation macros - everyone should use these. Please, steal these! Don't not use them and
don't rewrite them yourself!
*/
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
#define READ(x,y) ((0x00 == ((x & (1<<y))>> y))?0x00:0x01)
#define TOGGLE(x,y) (x ^= (1 << y))
int main(void)
{
//Variable to count the number of times the timer interrupt has fired
uint16_t ticks = 0;
uint16_t accel_data = 0;
uint8_t transmit_enable = 0x00;
uint8_t * uart_data_pointer = &accel_data;
/*Initialization Code*/
/* ATMega328 Datasheet Table 14-1 Pg 78
Configure PD7 for use as Heartbeat LED
Set as Output Low (initially)
*/
SET(DDRD,7); //Direction: output
CLEAR(PORTD,7); //State: Lo
/* TCCR1A - ATMega328 Datasheet Section 16.11.2 pg 134 - TCCR1A
No input capture used - bits 7:6 are 0
No waveform generation used - bits 4:3 are 0
Clock source select is bits 2:0 but are not yet set - wait until the
main loop is ready to start
*/
TCCR1A = 0x00;
/* TCCR1C - ATMega328 Datasheet Section 16.11.3 pg 135
This register is only used for output compare.
There's no output compare in this application so this can be all 0's
*/
TCCR1C = 0x00;
/* TCCR1B
Note: I've disabled the CKDIV8 fuse so that the clock source is 8MHz
As per ATMega328 Datasheet Section 16.9.1 page 123, setting the timer
to Normal mode causes the counter to count up until it reaches 0xFFFF
at which point it will overrun and start back at 0. To configure this
timer/counter to produce a period of 1ms we need to start counting
at a value that causes it to reach 65535 in 1ms.
What is that value?
With a clock prescaler of 32 each count of the timer is roughly
(1/8MHz)*32 = 1uS
1ms / 1us /tick = 1000 ticks /ms
The counter counts up to 65536, so to determine what value we have to
start at we subtract 1000 from 65536:
65536-1000 = 64536
*/
#define TIMER1_PERIOD 64536
TCNT1 = TIMER1_PERIOD;
//Configure ADC to read accelerometer data
//ATMega328 - Section 24.9.1 Pg 254 - ADMUX Register
/*ADC result - left-adjusted (Bit 5). The ADC result is 10-bits wide.
In practice, the least-significant 2 bits are often too noisy to be
of any use, so they are discarded. To support this, the ATMega328P is
capable of storing the upper eight bits of the ADC result in the
ADCH register alone. In this case, I want all 10 bits of the data
so I can show how to handle endianness in serial transmissions. As
a result, the most significant two bits are stored in ADCH and the least
significant 8 are stored in ADCL.
*/
/*ADC Channel - I only care about one - the Y axis on the accelerometer
which is channel 1.*/
ADMUX = (0x01 << 6) /*Reference - AVCC - 5V. */
|(0x00 << 5) /* Right-adjust ADC result - refer to
Section 24.9.3.2 pg 256*/
|(0x01 << 0); /*Channel set to X-Axis output on
accelerometer*/
/* ATMega328 Datasheet - Section 24.9.2 - ADCSRA - ADC Status
and Control Register
ADCEN - Bit 7 - Enable ADC - Obviously set this to 1
ADCSC - Bit 6 - Start Converstion - Not yet: 0
ADATE - Bit 5 - Auto-trigger ADC - I'll be manually triggering
the ADC, so 0
ADCIF - Bit 4 - ADC Interrupt Flag - Set when conversion
completes. Ignore.
ADCIE - Bit 3 - ADC Interrupt Enable - Everything will be polled
for this, so 0
ADPS - Bits 2:0 - ADC Prescaler
*/
/*ATMega328 Section 24.4 Pg245 discusses what the prescaler should be set to:
By default, the successive approximation circuitry requires an input clock
frequency between 50kHz and 200kHz to get maximum resolution.
The ClkIO is 8MHz and the prescaler options are 2,4,8,16,32,64 and 128.
1MHz/8 = ~125KHz, so that seems good. That value is 3
*/
ADCSRA = (0x01 << 7) //Enable ADC
|(0x03); //Set prescaler to 1/8 ClkIO - 125KHz
/* ATMega328 Datasheet Section 24.9.5 Pg 257 - DIDR0
This register allows digital input buffers on ADC pins to be
disabled. This saves power, so I'll do it
*/
DIDR0 = 0x01; //Turn off digital filtering on ADC channel 0
//Configure UART for 38400 8N1 Tx Communication
//Step 1 - Baud rate
/* ATMega328 Datasheet Section 20.10 - Table 20-6 pg 192
Baud rate settings for fosc of 8MHZ
Choosing baud rate of 38.4K for minimum error
U2Xn = 0 - Use standard (not double) data rate
UBRRn = 12
*/
UBRR0 = 12;
/* UCSR0A - UART 0 Control and Status Register A
ATMega328 Datasheet Section 20.11.2 pg 194
Bits 7:2 - Status bits
Bit 1 - Double UART transmission speed - No: 0
Bit 0 - Multi-Processor Communication Mode - No:0
*/
UCSR0A = 0x00;
/* UCSR0B - UART 0 Control and Status Register B
ATMega328 Datasheet Section 20.11.3 pg
Bit 7 - Rx Complete Interrupt Enable - 0
Bit 6 - Tx Complete Interrupt Enable - 0
Bit 5 - USART Data Register Empty interrupt enable - 0
Bit 4 - Receiver Enable - Set to 1
Bit 3 - Transmitter Enable - Set to 1
Bit 2 - Character Size Bit 2 - Set to 0 for 8 bits
Bit 1 - 9th receive bit - Ignore
Bit 0 - 9th transmit bit - Ignore
*/
UCSR0B = 0x00 | (1 << 3)
| (1 << 4);
/* UCSR0C - UART 0 Control and Status Register C
ATMega328 Datasheet Section 20.11.4 - Pg 196
Bits 7:6 - Set to asynchronous (clockless) mode: 00
Bits 5:4 - Parity setting - None : 00
Bit 3 - Stop select - 1 : 0
Bit 2:1 - Character size - 8 : 11
Bit 0 - Clock polarity: Don't care : 0
*/
UCSR0C = 0x03 << 1;
//Send a known pattern upon startup to verify the UART works
UDR0 = 0xA5;
//Wait until transmit is complete
while(0x00 == READ(UCSR0A,6));
UDR0 = 0x5A;
while(0x00 == READ(UCSR0A,6));
UDR0 = 0xA5;
//Wait until transmit is complete
while(0x00 == READ(UCSR0A,6));
/* Flash the LED for a second to show that initialization has successfully
occurred
*/
SET(PORTD,7);
_delay_ms(1000);
CLEAR(PORTD,7);
/* Start the timer/counter
ATMega328 Datasheet Section 16.11.2 Pg 135 - TCCR1B
No Waveform generation: bits 4:3 = 0
No input capture: bits 7:6 = 0
Clock select: ClkIO/8 - bits 2:0 = 010b = 0x02
*/
TCCR1B = 0x02; //This starts the counter/timer
while(1)
{
/* Timer overflow - Reading the accelerometer at a 1KHz rate
and flash the heartbeat LED at a reasonable period as well
*/
if(READ(TIFR1,0))
{
/* ATMega328 Datasheet Section 16.11.9 pg137
Setting TIFR1 bit 1 clears the overflow flag
*/
SET(TIFR1,0);
/* Reload the timer/counter count value to the
previous value so that the period remains the same
*/
TCNT1 = TIMER1_PERIOD;
//Read accelerometer data via ADC
SET(ADCSRA,6); //Start ADC conversion
/* Wait until conversion finishes - this should never
be more than 25*(8000000/8)^-1 seconds, which is
about 25us. Typical measured time is ~14.5us
*/
while(0x00 == READ(ADCSRA,4));
SET(ADCSRA,4); //Clear the interrupt flag by setting it to 1
//Clear acceleration data variable before loading new value
accel_data = 0;
/* When reading the full 10-bits from the ADC the
lower register must be read first
*/
accel_data |= (uint16_t)ADCL;
//Then the upper 2 bits
accel_data |= (uint16_t)(ADCH << 8);
/* Transmission of data is toggled by transmitting a
'0' (0x30) byte over serial
*/
if(0x01 == (READ(UCSR0A,7)))
{
if(0x30 == UDR0)
{
transmit_enable =
(0x00 == transmit_enable?0xFF:0x00);
}
}
if(0xFF == transmit_enable)
{
#ifdef BIG_ENDIAN
//Send high byte...
UDR0 = uart_data_pointer[1];
while(0x00 == READ(UCSR0A,6));
//...then low byte
UDR0 = uart_data_pointer[0];
while(0x00 == READ(UCSR0A,6));
#else
//Send low byte...
UDR0 = uart_data_pointer[0];
while(0x00 == READ(UCSR0A,6));
//...then high byte
UDR0 = uart_data_pointer[1];
while(0x00 == READ(UCSR0A,6));
#endif
}
//Blink Heartbeat LED
/*
The timer period is 1ms. To keep everything simple the LED will toggle
every 512 ticks - roughly every .5s.
*/
ticks++;
//If true, the current ticks is a multiple of 512
//So blink the heartbeat LED
if(0x8000 == (ticks << 7))
{
TOGGLE(PORTD,7);
}
}
//Main Loops
}
}
/**************************************************************************************/
/* sample usage of the library */
/**************************************************************************************/
//Remark: sys_timer_ticks should be provided for timing by the user.
/* Simplest example with undefined CONFIG_DEBOUNCE_WITH_HANDLE and CONFIG_DEBOUNCE_SEPARATE_TIMES */
#include <debounce.h>
#define INPUTS_NUM 12
nl_debouce_time_t inp_times[ INPUTS_NUM ];
nl_debouce_time_t filt_time = 10; //same value will be used for t_on and t_off
int main(void)
{
nl_inp_t inp_state, filtered_inp_state;
debounce_init( inp_times, INPUTS_NUM, &filt_time, &filt_time,
(nl_ticks_t*)&sys_timer_ticks );
while(1)
{
//user defined function, which return actual state of all inputs as bit array
inp_state = get_input_state();
debounce_proc(&inp_state, &filtered_inp_state);
//do something with filtered_inp_state
//...............
//main program functionality
//...............
}
}
/* More complex example with defined CONFIG_DEBOUNCE_WITH_HANDLE and CONFIG_DEBOUNCE_SEPARATE_TIMES */
#include <debounce.h>
#define INPUTS_NUM 5
struct debounce_state_s inp_dbnc_s;
nl_debouce_time_t inp_times[ INPUTS_NUM ];
nl_debouce_time_t t_on[ INPUTS_NUM ] = {10,10,20,20,50};
nl_debouce_time_t t_off[ INPUTS_NUM ] = {5,5,10,10,50};
int main(void)
{
nl_inp_t inp_state, filtered_inp_state;
debounce_init( &inp_dbnc_s, inp_times, INPUTS_NUM,
t_on, t_off, (nl_ticks_t*)&sys_timer_ticks );
while(1)
{
//user defined function, which return actual state of all inputs as bit array
inp_state = get_input_state();
debounce_proc(&inp_dbnc_s, &inp_state, &filtered_inp_state);
//do something with filtered_inp_state
//...............
//main program functionality
//...............
}
}
/**************************************************************************************/
/* debounce library header file "debounce.h" */
/**************************************************************************************/
#ifndef _DEBOUNCE_H_
#define _DEBOUNCE_H_
#include <stdint.h>
/* because library is multiplatform, following types are defined in separate file */
#include "nlib_types.h"
/* examaple of types definition in "nlib_types.h" */
//typedef uint32_t nl_ticks_t;
//typedef int16_t nl_debouce_time_t; //so maximum filter time is 32767ms (considering period of ticks 1ms)
//typedef uint32_t nl_inp_t; //up to 32 inputs can be handled
/* in general case following macros should be provided in this header file, or can be defined directly */
#include <debounce_config.h>
//#define CONFIG_DEBOUNCE_WITH_HANDLE
//#define CONFIG_DEBOUNCE_SEPARATE_TIMES
#ifdef CONFIG_DEBOUNCE_WITH_HANDLE
#define DEBOUNCE_STRUCT_PAR struct debounce_state_s * debounce_state,
#else
#define DEBOUNCE_STRUCT_PAR
#endif
typedef struct debounce_state_s
{
const nl_ticks_t* ticks; //pointer to timing variable (is incremented e.g. each 1ms)
nl_ticks_t old_ticks;
uint_fast8_t inp_num; //number of inputs
const nl_debouce_time_t *debounce_on_time,*debounce_off_time; //tables with desired filter times
nl_debouce_time_t* inp_times; //actual time ON/OFF - non-negative values = ON, negative = OFF
}
debounce_state_t;
void debounce_init(DEBOUNCE_STRUCT_PAR nl_debouce_time_t* inp_tim, uint_fast8_t num, const nl_debouce_time_t *dton,const nl_debouce_time_t *dtoff, const nl_ticks_t* ticks);
uint_fast8_t debounce_proc(DEBOUNCE_STRUCT_PAR const nl_inp_t* act_inp_state, nl_inp_t* debounced_inp_state);
#endif /*_DEBOUNCE_H_*/
/**************************************************************************************/
/* debounce library source file "debounce.c" */
/**************************************************************************************/
#include "debounce.h"
#include <string.h>
//allow using multiple instances
#ifndef CONFIG_DEBOUNCE_WITH_HANDLE
struct debounce_state_s _debounce_state_;
struct debounce_state_s * debounce_state = &_debounce_state_;
#endif
/* allow different times for each input */
#ifndef CONFIG_DEBOUNCE_SEPARATE_TIMES
#define _debounce_times_idx_ 0
#else
#define _debounce_times_idx_ i
#endif
//maco trick to find maximum value of given signed integer type "http://www.fefe.de/intof.html"
#define __HALF_MAX_SIGNED(type) ((type)1 << (sizeof(type)*8-2))
#define __MAX_SIGNED(type) (__HALF_MAX_SIGNED(type) - 1 + __HALF_MAX_SIGNED(type))
/*
Init function of the library
DEBOUNCE_STRUCT_PAR - depending on "CONFIG_DEBOUNCE_WITH_HANDLE": nothing, or pointer to handle
inp_tim - array of variables for storing of state for each input (number of elements must be the same as number of inputs!)
num - number of inputs
dton - depending on "CONFIG_DEBOUNCE_SEPARATE_TIMES": pointer to sigle value (minimal ON time), or array of times
dtoff - depending on "CONFIG_DEBOUNCE_SEPARATE_TIMES": pointer to sigle value (minimal OFF time), or array of times
ticks - pointer to variable, which is periodicaly incremented
*/
void debounce_init(DEBOUNCE_STRUCT_PAR nl_debouce_time_t* inp_tim, uint_fast8_t num, const nl_debouce_time_t *dton, const nl_debouce_time_t *dtoff ,const nl_ticks_t* ticks)
{
debounce_state-> inp_times=inp_tim;
debounce_state-> inp_num=num;
debounce_state-> debounce_on_time=dton;
debounce_state-> debounce_off_time=dtoff;
debounce_state-> ticks=ticks;
debounce_state-> old_ticks=*ticks;
memset(inp_tim,0,sizeof(*inp_tim)*num);
inp_tim[0]=__MAX_SIGNED(nl_debouce_time_t); //this is used later to evaluate first iteration after start
}
/*
This is core function of the library
DEBOUNCE_STRUCT_PAR - depending on "CONFIG_DEBOUNCE_WITH_HANDLE": nothing, or pointer to handle
act_inp_state - pointer to variable with actual state of all inputs (1 bit for each input)
debounced_inp_state - resulting state after filtering
return - 0=no change, 1=some input(s) are changed
*/
uint_fast8_t debounce_proc(DEBOUNCE_STRUCT_PAR const nl_inp_t* act_inp_state, nl_inp_t* debounced_inp_state)
{
uint_fast8_t i,change=0;
nl_inp_t mask=1;
nl_ticks_t tic_diff;
tic_diff=(nl_ticks_t) (*(debounce_state-> ticks) - debounce_state-> old_ticks);
debounce_state-> old_ticks = *(debounce_state-> ticks);
if ((debounce_state-> inp_times)[0] == __MAX_SIGNED(nl_debouce_time_t)) //evaluate, if it is a first iteration
{
*debounced_inp_state=*act_inp_state;
for(i=0; i<debounce_state-> inp_num ;i++)
(debounce_state-> inp_times)[i]=0;
return 0;
}
for(i=0; i<debounce_state-> inp_num ;i++)
{
if ( *act_inp_state & mask) //actual state is ON
{
if ((debounce_state-> inp_times)[i] >= 0) //and last state was ON
{
if (((debounce_state-> inp_times)[i] + (nl_debouce_time_t) tic_diff) < debounce_state-> debounce_on_time[_debounce_times_idx_])
{
(debounce_state-> inp_times)[i] += (nl_debouce_time_t) tic_diff; //filter time not elapsed
}
else
{ //filter time elapsed
if (!( *debounced_inp_state & mask))
{
*debounced_inp_state |= mask;
change=1;
}
}
}
else (debounce_state-> inp_times)[i] = 0;
}
else //actual state is OFF
{
if (debounce_state-> inp_times[i] < 0) //and last state was OFF
{
if ( (nl_debouce_time_t)(((debounce_state-> inp_times)[i] - (nl_debouce_time_t) tic_diff)) >= (-1*debounce_state-> debounce_off_time[_debounce_times_idx_]))
{
(debounce_state-> inp_times)[i] -= (nl_debouce_time_t) tic_diff; //filter time not elapsed
}
else
{ //filter time elapsed
if ( *debounced_inp_state & mask)
{
*debounced_inp_state &= ~mask;
change=1;
}
}
}
else (debounce_state-> inp_times)[i] = -1;
}
mask=(nl_inp_t) mask<<1;
}
return change;
}
#include <string.h>
#include <stdint.h>
//This is a helper function to convert a six-bit value to base64
char base64_encode_six(uint8_t six_bit_value){
uint8_t x;
char c;
x = six_bit_value & ~0xC0; //remove top two bits (should be zero anyway)
if( x < 26 ){
c = 'A' + x;
} else if ( x < 52 ){
c = 'a' + (x - 26);
} else if( x < 62 ){
c = '0' + (x - 52);
} else if( x == 62 ){
c = '+';
} else if (x == 63 ){
c = '/';
} else {
printf("ERROR IN BASE 64\n");
c = 'A';
}
return c;
}
//This is the function for encoding in base64
void base64_encode(char * dest, const char * src){
int bits;
int i;
int j;
int k;
int len;
uint8_t six_bits[4];
len = strlen(src);
k = 0;
//We need to encode three bytes at a time in to four encoded bytes
for(i=0; i < len; i+=3){
//First the thress bytes are broken down into six-bit sections
six_bits[0] = (src[i] >> 2) & 0x3F;
six_bits[1] = ((src[i] << 4) & 0x30) + ((src[i+1]>>4) & 0x0F);
six_bits[2] = ((src[i+1] << 2) & 0x3C) + ((src[i+2]>>6) & 0x03);
six_bits[3] = src[i+2] & 0x3F;
//now we use the helper function to convert from six-bits to base64
for(j=0; j < 4; j++){
dest[k+j] = base64_encode_six(six_bits[j]);
}
k+=4;
}
//at the end, we add = if the input is not divisible by 3
if( (len % 3) == 1 ){
//two equals at end
dest[k-2] = '=';
dest[k-1] = '=';
} else if ( (len %3 ) == 2 ){
dest[k-1] = '=';
}
//finally, zero terminate the output string
dest[k] = 0;
}
/**@file led_blink.c
@brief The most basic approach to blinking an LED on AVR microcontrollers - specifically the ATMega328P
@author Stephen Friederichs
@date 3/28/13
@note This code assumes that the LED is active high (pin sources current)
*/
/**@def F_CPU
@brief Clock frequency = 8MHZ - this is set by fuses and registers, not by this define
@note Always define this before including delay.h!
*/
#define F_CPU 8000000
/**@include io.h
@brief Include for AVR I/O register definitions
*/
#include <avr/io.h>
/**@include stdint.h
@brief Include for standard integer definitions (ie, uint8_t, int32_t, etc)
*/
#include <stdint.h>
/**@include delay.h
@brief Include for delay functions such as _delay_ms() and _delay_us()
*/
#include <util/delay.h>
/* Basic bit manipulation macros - everyone should use these. Please, steal these! Don't not use them and
don't rewrite them yourself!
*/
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
#define READ(x,y) ((FALSE == ((x & (1<<y))>> y))?FALSE:TRUE)
#define TOGGLE(x,y) (x ^= (1<<y))
int main(void)
{
/*Initialization Code*/
/* ATMega328 Datasheet Table 14-1 Pg 78
Configure PD7 for use as Heartbeat LED
Set as Output Low (initially)
*/
SET(DDRD,7); //Direction: output
CLEAR(PORTD,7); //State: Lo
/* Flash the LED for a second to show that initialization has successfully
occurred
*/
SET(PORTD,7);
_delay_ms(1000);
CLEAR(PORTD,7);
while(1)
{
/*Set PD7 low for 500ms*/
CLEAR(PORTD,7);
_delay_ms(500);
/*Then set it high for 500ms*/
SET(PORTD,7);
_delay_ms(500);
/*Before repeating the process forever...*/
}
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_PROCESSES 32 /* the maximal number of processes in the system */
#define MAX_NAME_LEN 32
/* Process control block -
* holding all process relevant informations
*/
struct pcb{
int pid; /* ID of the proces */
int prio; /* process priority */
int attached; /* 1 if attached to processlist, else 0 */
int *function; /* pointer to the process function */
char name[MAX_NAME_LEN]; /* Name of the process */
};
static struct pcb processlist[MAX_PROCESSES];
int process0();
int process1();
int process_attach(char *name, int prio, void *function)
{
int i = 0;
int ret = -1;
printf("[dbg] process_attach\n");
while(i < MAX_PROCESSES) {
if(strlen(name) > MAX_NAME_LEN) {
printf("[err] wrong stringlen\n");
return ret;
}
if(processlist[i].attached != 1) {
printf("attach process at %d\n", i);
processlist[i].pid = i;
strcpy(processlist[i].name, name);
processlist[i].prio = prio;
processlist[i].function = function;
processlist[i].attached = 1;
ret = 0;
break;
}
printf("\n");
i++;
}
return ret;
}
int process_detach(int pid)
{
processlist[pid].attached = 0;
return 0;
}
/*
* basic implementation of a RR scheduler
*/
int scheduler()
{
int i = 0;
void (*p)(void);
while(1) {
for(i = 0; i < MAX_PROCESSES; i++) {
if(processlist[i].attached == 1) {
p = (void *)processlist[i].function;
(*p)();
}
}
}
return 0;
}
/*** Testdriver ***/
int process0()
{
printf("0\n");
return 0;
}
int process1()
{
printf("1\n");
return 0;
}
int main()
{
/*
* test run here
* */
printf("basic_scheduler Demo\n");
process_attach("process0", 100, process0);
process_attach("process1", 50, process1);
scheduler();
return 0;
}
/**************************************************************************************/
/* sample usage of the library */
/**************************************************************************************/
//Remark: sys_timer_ticks should be provided for timing by the user.
/* Simplest example with undefined CONFIG_DEBOUNCE_WITH_HANDLE and CONFIG_DEBOUNCE_SEPARATE_TIMES */
#include <debounce.h>
#define INPUTS_NUM 12
nl_debouce_time_t inp_times[ INPUTS_NUM ];
nl_debouce_time_t filt_time = 10; //same value will be used for t_on and t_off
int main(void)
{
nl_inp_t inp_state, filtered_inp_state;
debounce_init( inp_times, INPUTS_NUM, &filt_time, &filt_time,
(nl_ticks_t*)&sys_timer_ticks );
while(1)
{
//user defined function, which return actual state of all inputs as bit array
inp_state = get_input_state();
debounce_proc(&inp_state, &filtered_inp_state);
//do something with filtered_inp_state
//...............
//main program functionality
//...............
}
}
/* More complex example with defined CONFIG_DEBOUNCE_WITH_HANDLE and CONFIG_DEBOUNCE_SEPARATE_TIMES */
#include <debounce.h>
#define INPUTS_NUM 5
struct debounce_state_s inp_dbnc_s;
nl_debouce_time_t inp_times[ INPUTS_NUM ];
nl_debouce_time_t t_on[ INPUTS_NUM ] = {10,10,20,20,50};
nl_debouce_time_t t_off[ INPUTS_NUM ] = {5,5,10,10,50};
int main(void)
{
nl_inp_t inp_state, filtered_inp_state;
debounce_init( &inp_dbnc_s, inp_times, INPUTS_NUM,
t_on, t_off, (nl_ticks_t*)&sys_timer_ticks );
while(1)
{
//user defined function, which return actual state of all inputs as bit array
inp_state = get_input_state();
debounce_proc(&inp_dbnc_s, &inp_state, &filtered_inp_state);
//do something with filtered_inp_state
//...............
//main program functionality
//...............
}
}
/**************************************************************************************/
/* debounce library header file "debounce.h" */
/**************************************************************************************/
#ifndef _DEBOUNCE_H_
#define _DEBOUNCE_H_
#include <stdint.h>
/* because library is multiplatform, following types are defined in separate file */
#include "nlib_types.h"
/* examaple of types definition in "nlib_types.h" */
//typedef uint32_t nl_ticks_t;
//typedef int16_t nl_debouce_time_t; //so maximum filter time is 32767ms (considering period of ticks 1ms)
//typedef uint32_t nl_inp_t; //up to 32 inputs can be handled
/* in general case following macros should be provided in this header file, or can be defined directly */
#include <debounce_config.h>
//#define CONFIG_DEBOUNCE_WITH_HANDLE
//#define CONFIG_DEBOUNCE_SEPARATE_TIMES
#ifdef CONFIG_DEBOUNCE_WITH_HANDLE
#define DEBOUNCE_STRUCT_PAR struct debounce_state_s * debounce_state,
#else
#define DEBOUNCE_STRUCT_PAR
#endif
typedef struct debounce_state_s
{
const nl_ticks_t* ticks; //pointer to timing variable (is incremented e.g. each 1ms)
nl_ticks_t old_ticks;
uint_fast8_t inp_num; //number of inputs
const nl_debouce_time_t *debounce_on_time,*debounce_off_time; //tables with desired filter times
nl_debouce_time_t* inp_times; //actual time ON/OFF - non-negative values = ON, negative = OFF
}
debounce_state_t;
void debounce_init(DEBOUNCE_STRUCT_PAR nl_debouce_time_t* inp_tim, uint_fast8_t num, const nl_debouce_time_t *dton,const nl_debouce_time_t *dtoff, const nl_ticks_t* ticks);
uint_fast8_t debounce_proc(DEBOUNCE_STRUCT_PAR const nl_inp_t* act_inp_state, nl_inp_t* debounced_inp_state);
#endif /*_DEBOUNCE_H_*/
/**************************************************************************************/
/* debounce library source file "debounce.c" */
/**************************************************************************************/
#include "debounce.h"
#include <string.h>
//allow using multiple instances
#ifndef CONFIG_DEBOUNCE_WITH_HANDLE
struct debounce_state_s _debounce_state_;
struct debounce_state_s * debounce_state = &_debounce_state_;
#endif
/* allow different times for each input */
#ifndef CONFIG_DEBOUNCE_SEPARATE_TIMES
#define _debounce_times_idx_ 0
#else
#define _debounce_times_idx_ i
#endif
//maco trick to find maximum value of given signed integer type "http://www.fefe.de/intof.html"
#define __HALF_MAX_SIGNED(type) ((type)1 << (sizeof(type)*8-2))
#define __MAX_SIGNED(type) (__HALF_MAX_SIGNED(type) - 1 + __HALF_MAX_SIGNED(type))
/*
Init function of the library
DEBOUNCE_STRUCT_PAR - depending on "CONFIG_DEBOUNCE_WITH_HANDLE": nothing, or pointer to handle
inp_tim - array of variables for storing of state for each input (number of elements must be the same as number of inputs!)
num - number of inputs
dton - depending on "CONFIG_DEBOUNCE_SEPARATE_TIMES": pointer to sigle value (minimal ON time), or array of times
dtoff - depending on "CONFIG_DEBOUNCE_SEPARATE_TIMES": pointer to sigle value (minimal OFF time), or array of times
ticks - pointer to variable, which is periodicaly incremented
*/
void debounce_init(DEBOUNCE_STRUCT_PAR nl_debouce_time_t* inp_tim, uint_fast8_t num, const nl_debouce_time_t *dton, const nl_debouce_time_t *dtoff ,const nl_ticks_t* ticks)
{
debounce_state-> inp_times=inp_tim;
debounce_state-> inp_num=num;
debounce_state-> debounce_on_time=dton;
debounce_state-> debounce_off_time=dtoff;
debounce_state-> ticks=ticks;
debounce_state-> old_ticks=*ticks;
memset(inp_tim,0,sizeof(*inp_tim)*num);
inp_tim[0]=__MAX_SIGNED(nl_debouce_time_t); //this is used later to evaluate first iteration after start
}
/*
This is core function of the library
DEBOUNCE_STRUCT_PAR - depending on "CONFIG_DEBOUNCE_WITH_HANDLE": nothing, or pointer to handle
act_inp_state - pointer to variable with actual state of all inputs (1 bit for each input)
debounced_inp_state - resulting state after filtering
return - 0=no change, 1=some input(s) are changed
*/
uint_fast8_t debounce_proc(DEBOUNCE_STRUCT_PAR const nl_inp_t* act_inp_state, nl_inp_t* debounced_inp_state)
{
uint_fast8_t i,change=0;
nl_inp_t mask=1;
nl_ticks_t tic_diff;
tic_diff=(nl_ticks_t) (*(debounce_state-> ticks) - debounce_state-> old_ticks);
debounce_state-> old_ticks = *(debounce_state-> ticks);
if ((debounce_state-> inp_times)[0] == __MAX_SIGNED(nl_debouce_time_t)) //evaluate, if it is a first iteration
{
*debounced_inp_state=*act_inp_state;
for(i=0; i<debounce_state-> inp_num ;i++)
(debounce_state-> inp_times)[i]=0;
return 0;
}
for(i=0; i<debounce_state-> inp_num ;i++)
{
if ( *act_inp_state & mask) //actual state is ON
{
if ((debounce_state-> inp_times)[i] >= 0) //and last state was ON
{
if (((debounce_state-> inp_times)[i] + (nl_debouce_time_t) tic_diff) < debounce_state-> debounce_on_time[_debounce_times_idx_])
{
(debounce_state-> inp_times)[i] += (nl_debouce_time_t) tic_diff; //filter time not elapsed
}
else
{ //filter time elapsed
if (!( *debounced_inp_state & mask))
{
*debounced_inp_state |= mask;
change=1;
}
}
}
else (debounce_state-> inp_times)[i] = 0;
}
else //actual state is OFF
{
if (debounce_state-> inp_times[i] < 0) //and last state was OFF
{
if ( (nl_debouce_time_t)(((debounce_state-> inp_times)[i] - (nl_debouce_time_t) tic_diff)) >= (-1*debounce_state-> debounce_off_time[_debounce_times_idx_]))
{
(debounce_state-> inp_times)[i] -= (nl_debouce_time_t) tic_diff; //filter time not elapsed
}
else
{ //filter time elapsed
if ( *debounced_inp_state & mask)
{
*debounced_inp_state &= ~mask;
change=1;
}
}
}
else (debounce_state-> inp_times)[i] = -1;
}
mask=(nl_inp_t) mask<<1;
}
return change;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_PROCESSES 32 /* the maximal number of processes in the system */
#define MAX_NAME_LEN 32
/* Process control block -
* holding all process relevant informations
*/
struct pcb{
int pid; /* ID of the proces */
int prio; /* process priority */
int attached; /* 1 if attached to processlist, else 0 */
int *function; /* pointer to the process function */
char name[MAX_NAME_LEN]; /* Name of the process */
};
static struct pcb processlist[MAX_PROCESSES];
int process0();
int process1();
int process_attach(char *name, int prio, void *function)
{
int i = 0;
int ret = -1;
printf("[dbg] process_attach\n");
while(i < MAX_PROCESSES) {
if(strlen(name) > MAX_NAME_LEN) {
printf("[err] wrong stringlen\n");
return ret;
}
if(processlist[i].attached != 1) {
printf("attach process at %d\n", i);
processlist[i].pid = i;
strcpy(processlist[i].name, name);
processlist[i].prio = prio;
processlist[i].function = function;
processlist[i].attached = 1;
ret = 0;
break;
}
printf("\n");
i++;
}
return ret;
}
int process_detach(int pid)
{
processlist[pid].attached = 0;
return 0;
}
/*
* basic implementation of a RR scheduler
*/
int scheduler()
{
int i = 0;
void (*p)(void);
while(1) {
for(i = 0; i < MAX_PROCESSES; i++) {
if(processlist[i].attached == 1) {
p = (void *)processlist[i].function;
(*p)();
}
}
}
return 0;
}
/*** Testdriver ***/
int process0()
{
printf("0\n");
return 0;
}
int process1()
{
printf("1\n");
return 0;
}
int main()
{
/*
* test run here
* */
printf("basic_scheduler Demo\n");
process_attach("process0", 100, process0);
process_attach("process1", 50, process1);
scheduler();
return 0;
}
/**@file timer_blinker.c
@brief A more advanced LED blinker using a timer
@author Stephen Friederichs
@date 3/28/13
@note This code assumes that the LED is active high (pin sources current)
*/
/**@def F_CPU
@brief Clock frequency = 8MHZ - this is set by fuses and registers, not by this define
@note Always define this before including delay.h!
*/
#define F_CPU 8000000
/**@include io.h
@brief Include for AVR I/O register definitions
*/
#include <avr/io.h>
/**@include stdint.h
@brief Include for standard integer definitions (ie, uint8_t, int32_t, etc)
*/
#include <stdint.h>
/**@include delay.h
@brief Include for delay functions such as _delay_ms() and _delay_us()
*/
#include <util/delay.h>
/* Basic bit manipulation macros - everyone should use these. Please, steal these! Don't not use them and
don't rewrite them yourself!
*/
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
#define READ(x,y) ((0x00 == ((x & (1<<y))>> y))?0x00:0x01)
#define TOGGLE(x,y) (x ^= (1<<y))
int main(void)
{
/*Initialization Code*/
/* ATMega328 Datasheet Table 14-1 Pg 78
Configure PD7 for use as Heartbeat LED
Set as Output Low (initially)
*/
SET(DDRD,7); //Direction: output
CLEAR(PORTD,7); //State: Lo
/* TCCR1A - ATMega328 Datasheet Section 16.11.1 pg 132
No waveform generation is required on this timer, so set all
ports to normal operation
*/
TCCR1A = 0x00;
/* TCCR1C - ATMega328 Datasheet Section 16.11.3 pg 135
This register is only used for output compare.
There's no output compare in this application so this can be all 0's
*/
TCCR1C = 0x00;
/* TCCR1B
Note: I've disabled the CKDIV8 fuse so that the clock source is 8MHz
ATMega328 Datasheet Section 16.11.2 pg 134 - TCCR1A
No input capture used - bits 7:6 are 0
No waveform generation used - bits 4:3 are 0
Clock source select is bits 2:0 but are not yet set - wait until the
main loop is ready to start
As per ATMega328 Datasheet Section 16.9.1 page 123, setting the timer
to Normal mode causes the counter to count up until it reaches 0xFFFF
at which point it will overrun and start back at 0. To configure this
timer/counter to produce a period of 500ms we need to start counting
at a value that causes it to reach 65535 in 500ms.
What is that value?
With a clock prescaler of 256 each count of the timer is roughly
(1/8MHz)*256 = 32uS
500ms / 32us /tick = 15625 ticks /500ms
The counter counts up to 65535, so to determine what value we have to
start at we subtract 15635 from 65536:
65536-15625 = 49910
*/
#define TIMER1_PERIOD 49910
TCNT1 = TIMER1_PERIOD;
/* Flash the LED for a second to show that initialization has successfully
occurred
*/
SET(PORTD,7);
_delay_ms(1000);
CLEAR(PORTD,7);
/* Start the timer/counter
ATMega328 Datasheet Section 16.11.2 Pg 135 - TCCR1B
No Waveform generation: bits 4:3 = 0
No input capture: bits 7:6 = 0
Clock select: ClkIO/256 - bits 2:0 = 100b = 0x04
*/
TCCR1B = 0x04; //This starts the counter/timer
while(1)
{
/* Handle the Heartbeat LED
When the timer/counter reaches 65535 the 500ms period will have
elapsed and TIFR1 bit 1 will be '1'
*/
if(READ(TIFR1,0))
{
/* ATMega328 Datasheet Section 16.11.9 pg137
Setting TIFR1 bit 1 clears the overflow flag
*/
SET(TIFR1,0);
/* Toggle the LED to flash it at 1Hz*/
TOGGLE(PORTD,7);
/* Reload the timer/counter count value to the previous value
so that the period remains the same
*/
TCNT1 = TIMER1_PERIOD;
}
/* Now you can do useful work here - no delay loops!*/
}
}
/**@file led_blink.c
@brief The most basic approach to blinking an LED on AVR microcontrollers - specifically the ATMega328P
@author Stephen Friederichs
@date 3/28/13
@note This code assumes that the LED is active high (pin sources current)
*/
/**@def F_CPU
@brief Clock frequency = 8MHZ - this is set by fuses and registers, not by this define
@note Always define this before including delay.h!
*/
#define F_CPU 8000000
/**@include io.h
@brief Include for AVR I/O register definitions
*/
#include <avr/io.h>
/**@include stdint.h
@brief Include for standard integer definitions (ie, uint8_t, int32_t, etc)
*/
#include <stdint.h>
/**@include delay.h
@brief Include for delay functions such as _delay_ms() and _delay_us()
*/
#include <util/delay.h>
/* Basic bit manipulation macros - everyone should use these. Please, steal these! Don't not use them and
don't rewrite them yourself!
*/
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
#define READ(x,y) ((FALSE == ((x & (1<<y))>> y))?FALSE:TRUE)
#define TOGGLE(x,y) (x ^= (1<<y))
int main(void)
{
/*Initialization Code*/
/* ATMega328 Datasheet Table 14-1 Pg 78
Configure PD7 for use as Heartbeat LED
Set as Output Low (initially)
*/
SET(DDRD,7); //Direction: output
CLEAR(PORTD,7); //State: Lo
/* Flash the LED for a second to show that initialization has successfully
occurred
*/
SET(PORTD,7);
_delay_ms(1000);
CLEAR(PORTD,7);
while(1)
{
/*Set PD7 low for 500ms*/
CLEAR(PORTD,7);
_delay_ms(500);
/*Then set it high for 500ms*/
SET(PORTD,7);
_delay_ms(500);
/*Before repeating the process forever...*/
}
}
/**
* @file
* Software timer facility.
*
* This module implements an unlimited number of 8-bit down-counting 10ms and
* 100ms timers. Timers are actually held in various places by the application
* code and are registered with this module for service from the system's
* timekeeping interrupt.
*
* A down-counting timer starts out set to a time interval and is
* automatically decremented via the system's periodic interrupt. Check for a
* zero value to know when the timer has expired:
*
* <pre>uint8_t my_timer = 10;
* timer_register_100ms(&my_timer);
*
* for (;;)
* {
* if (my_timer == 0)
* {
* do_something();
* my_timer = 10;
* }
* }</pre>
*
* Down-counting timers are restricted to 8 bits so that they can be
* atomically manipulated outside interrupt code on 8-bit architectures
* without resorting to disable interrupts.
*
* @warning All variables used as timers must be declared
* <code>volatile</code>, because they are modified from an interrupt
* context that may not be understood by the compiler. GCC in
* particular is known to optimize away timer variables that aren't
* declared <code>volatile</code>.
*
* <h2>Configuration</h2>
* The number of available 10ms and 100ms timer slots is set using
* {@link MAX_100MS_TIMERS} and {@link MAX_10MS_TIMERS}.
*/
#include <stdlib.h> /* for NULL */
#include <stdint.h> /* uint8_t, etc. */
#include <stdbool.h> /* bool type, true, false */
#include "timer.h"
/** Maximum number of 100ms timers that can be registered. */
#define MAX_100MS_TIMERS 10
/** Maximum number of 10ms timers that can be registered. */
#define MAX_10MS_TIMERS 10
/** The polling frequency for the 10ms timers is scaled by this factor to
service the 100ms timers. */
#define PRESCALE_100MS 10
/* ------------------------------------------------------------------------ */
/** 10ms timer array. These are pointers to the actual timers elsewhere in
the application code. */
static volatile uint8_t *timers_10ms [MAX_10MS_TIMERS];
/** 100ms timer array. These are pointers to the actual timers elsewhere in
the application code. */
static volatile uint8_t *timers_100ms [MAX_100MS_TIMERS];
bool timer_register_10ms (volatile uint8_t *t)
{
uint8_t k;
for (k = 0; k < MAX_10MS_TIMERS; ++k)
{
if (NULL == timers_10ms[k])
{
/* Success--found an unused slot */
timers_10ms[k] = t;
return false;
}
}
/* Failure */
return true;
}
bool timer_register_100ms (volatile uint8_t *t)
{
uint8_t k;
for (k = 0; k < MAX_100MS_TIMERS; ++k)
{
if (NULL == timers_100ms[k])
{
/* Success--found an unused slot */
timers_100ms[k] = t;
return false;
}
}
/* Failure */
return true;
}
void timer_poll (void)
{
static uint8_t prescaler = PRESCALE_100MS;
volatile uint8_t *t;
uint8_t k;
/* Service the 10ms timers */
for (k = 0; k < MAX_10MS_TIMERS; ++k)
{
t = timers_10ms[k];
/* First NULL entry marks the end of the registered timers */
if (t == NULL)
{
break;
}
if (*t > 0)
{
-- *t;
}
}
/* Now divide the frequency by 10 and service the 100ms timers every 10th
time through. */
if (--prescaler == 0)
{
prescaler = PRESCALE_100MS;
for (k = 0; k < MAX_100MS_TIMERS; ++k)
{
t = timers_100ms[k];
if (t == NULL)
{
break;
}
if (*t > 0)
{
-- *t;
}
}
}
}
/* Header file */
#if !defined(TIMER_H)
#define TIMER_H
/**
* @file
*/
#include <stdbool.h>
#include <stdlib.h>
/**
* Registers a 10-millisecond timer for service.
*
* @param[in] t pointer to the variable used for timing
*
* @retval true if registration failed
* @retval false if registration succeeded (normal return)
*/
bool timer_register_10ms (volatile uint8_t *t);
/**
* Registers a 100-millisecond timer for service.
*
* @param[in] t pointer to the variable used for timing
*
* @retval true if registration failed
* @retval false if registration succeeded (normal return)
*/
bool timer_register_100ms (volatile uint8_t *t);
/**
* Maintains all registered timers.
*
* This function should be called from a stable 10-millisecond time base,
* preferably from an interrupt.
*/
void timer_poll (void);
#endif /* TIMER_H */