Moved libraries to lib directory, added hardware abstraction lib
This commit is contained in:
parent
9810b13d17
commit
8dc4c5bbc7
|
@ -4,12 +4,13 @@
|
|||
|
||||
#curl http://seb.exse.net/ledtest.hex > ledtest.hex && avrflash.sh m168 -F -v -v -U flash:w:ledtest.hex
|
||||
|
||||
#MCU = atmega88p
|
||||
#MCU = atmega328p
|
||||
|
||||
#MCU = atmega644
|
||||
F_CPU = 8000000
|
||||
MCU = atmega88p
|
||||
|
||||
#F_CPU = 20000000
|
||||
F_CPU = 8000000
|
||||
|
||||
QUARZ = 8MHZ
|
||||
|
||||
#internal RC/8
|
||||
|
@ -35,7 +36,7 @@ OPT = s
|
|||
|
||||
##########################################################################################################
|
||||
# List C source files here. (C dependencies are automatically generated.)
|
||||
SRC = main.c lib/synth.c lib/usart.c
|
||||
SRC = main.c lib/synth.c lib/usart.c lib/bughal.c
|
||||
##########################################################################################################
|
||||
|
||||
|
||||
|
|
39
firmware/lib/bughal.c
Normal file
39
firmware/lib/bughal.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include <inttypes.h>
|
||||
#include "bughal.h"
|
||||
|
||||
/* Hardware abstraction layer for Pentabug hardware */
|
||||
|
||||
/*
|
||||
* initialize LEDs on C0-C3
|
||||
*/
|
||||
void init_leds(void){
|
||||
//enable LED channels as output
|
||||
DDRC |= (1 << PORTC0) | (1 << PORTC1) | (1 << PORTC2) | (1 << PORTC3);
|
||||
// both LEDs off
|
||||
PORTC &= ~(1 << PORTC0) | (1 << PORTC1) | (1 << PORTC2) | (1 << PORTC3);
|
||||
|
||||
|
||||
//TCCR2A = (1 << WGM21);
|
||||
//TCCR2B = (1 << CS20)|(1 << CS21);
|
||||
//OCR2A = 255; /* TOP */
|
||||
// TCNT2 = 0;
|
||||
// /*enable interrupt*/
|
||||
// TIMSK2 |= (1<<OCIE2A);
|
||||
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
void init_buzzr(int mode);
|
||||
|
||||
|
||||
void init_switch();
|
||||
|
||||
static void init_motor(void)
|
||||
{
|
||||
/* vibration motor on B1, initially off: */
|
||||
DDRB |= (1 << PORTB1);
|
||||
PORTB &= ~( 1<<PORTB1);
|
||||
return;
|
||||
}
|
||||
|
17
firmware/lib/bughal.h
Normal file
17
firmware/lib/bughal.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef BUGHAL_H
|
||||
#define BUGHAL_H
|
||||
|
||||
/* Hardware abstraction layer for Pentabug hardware */
|
||||
|
||||
enum { BUZZR_OUT, //initialize buzzer for OUTPUT mode (emmiting soundwaves)
|
||||
BUZZR_IN //initialize buzzer for INPUT mode (registering soundwaves)
|
||||
};
|
||||
|
||||
|
||||
|
||||
void init_leds(void);
|
||||
void init_buzzr(int);
|
||||
void init_switch(void);
|
||||
void init_motor(void);
|
||||
|
||||
#endif
|
324
firmware/lib/synth.c
Normal file
324
firmware/lib/synth.c
Normal file
|
@ -0,0 +1,324 @@
|
|||
#include <inttypes.h>
|
||||
#include "synth.h"
|
||||
#include "freq_table.h"
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
// sample rate is 8M / (3 * 64)
|
||||
|
||||
enum {
|
||||
channel_count = 3,
|
||||
//tick_length = 400,
|
||||
// tick_length = 256,
|
||||
row_length = 4,
|
||||
pattern_length = 16
|
||||
};
|
||||
|
||||
|
||||
|
||||
static const synth_instrument_t instruments[] = {
|
||||
{ 1<<15, 100, 12 },
|
||||
{ 0, 100, 12 },
|
||||
{ 0, 200, 10 },
|
||||
{ 1<<13, 0, 0, 2 },
|
||||
{ 1<<13, 0, 5, 2 },
|
||||
};
|
||||
|
||||
static const uint8_t wave_table[][2] = {
|
||||
{ 0, WAVE_PULSE },
|
||||
{ 3, WAVE_PULSE },
|
||||
{ 7, WAVE_PULSE },
|
||||
{ 12, WAVE_PULSE },
|
||||
{ 256 - 4, 0xff },
|
||||
|
||||
{ 0, WAVE_PULSE },
|
||||
{ 2, WAVE_PULSE },
|
||||
{ 7, WAVE_PULSE },
|
||||
{ 10, WAVE_PULSE },
|
||||
{ 256 - 4, 0xff },
|
||||
|
||||
{ 0, WAVE_NOISE },
|
||||
{ 0, WAVE_PULSE },
|
||||
{ 0xff, 0xff },
|
||||
|
||||
{ 0, WAVE_PULSE },
|
||||
{ 0xff, 0xff },
|
||||
|
||||
};
|
||||
|
||||
|
||||
static const uint8_t patterns[][pattern_length][2] PROGMEM = {
|
||||
{},
|
||||
{
|
||||
{ 33 - 12, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0xff, 1 },
|
||||
{ 0, 0 },
|
||||
{ 33, 1 },
|
||||
{ 0xff, 1 },
|
||||
{ 33, 1 },
|
||||
{ 0xff, 1 },
|
||||
{ 33, 1 },
|
||||
{ 0xff, 1 },
|
||||
{ 33 - 12, 1 },
|
||||
{ 0xff, 1 },
|
||||
{ 33 - 12, 1 },
|
||||
{ 0xff, 1 },
|
||||
{ 33, 1 },
|
||||
{ 0xff, 1 },
|
||||
},
|
||||
{
|
||||
{ 28 - 12, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0xff, 1 },
|
||||
{ 0, 0 },
|
||||
{ 28, 1 },
|
||||
{ 0xff, 1 },
|
||||
{ 28, 1 },
|
||||
{ 0xff, 1 },
|
||||
{ 28, 1 },
|
||||
{ 0xff, 1 },
|
||||
{ 28 - 12, 1 },
|
||||
{ 0xff, 1 },
|
||||
{ 28 - 12, 1 },
|
||||
{ 0xff, 1 },
|
||||
{ 28, 1 },
|
||||
{ 0xff, 1 },
|
||||
},
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 57, 3 },
|
||||
},
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 57, 4 },
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
{ 60, 2 },
|
||||
},
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 57, 2 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 55, 2 },
|
||||
{ 0, 0 },
|
||||
{ 57, 2 },
|
||||
{ 0, 0 },
|
||||
},
|
||||
{
|
||||
{ 55, 2 },
|
||||
},
|
||||
{
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 57, 2 },
|
||||
},
|
||||
{
|
||||
{ 55-3, 2 },
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
static const uint8_t pattern_table[][channel_count] = {
|
||||
{ 1, 0, 5 },
|
||||
{ 1, 3, 0 },
|
||||
{ 1, 0, 7 },
|
||||
{ 1, 3, 6 },
|
||||
{ 2, 0, 7 },
|
||||
{ 2, 4, 8 },
|
||||
{ 2, 0, 9 },
|
||||
{ 2, 4, 0 },
|
||||
};
|
||||
enum {
|
||||
pattern_table_length = sizeof(pattern_table) / sizeof(pattern_table[0])
|
||||
};
|
||||
|
||||
|
||||
static synth_channel_t channels[channel_count];
|
||||
static int8_t sample;
|
||||
static int8_t tick;
|
||||
static int8_t row;
|
||||
static int8_t seq;
|
||||
|
||||
|
||||
/* PROTOTYPES */
|
||||
uint8_t synth_mix(void);
|
||||
|
||||
static uint8_t timeslots[SYNTH_BUFSIZE];
|
||||
static uint8_t timeslots_write; // current write head
|
||||
static uint8_t timeslots_read; // current read head
|
||||
|
||||
/*register for atomic ++ and -- */
|
||||
register uint8_t timeslots_fill asm("r2");
|
||||
|
||||
|
||||
static void enqueue_timeslot(uint8_t synthval);
|
||||
static uint8_t dequeue_timeslot(void);
|
||||
|
||||
void synth_init(void)
|
||||
{
|
||||
sample = 0;
|
||||
tick = 0;
|
||||
row = 0;
|
||||
seq = 0;
|
||||
timeslots_fill = 0;
|
||||
}
|
||||
|
||||
inline uint8_t synth_mix(void)
|
||||
{
|
||||
if(sample == 0) { // new tick
|
||||
for(int i = 1; i < channel_count; i++) {
|
||||
synth_channel_t* chan = &channels[i];
|
||||
|
||||
const synth_instrument_t* inst = &instruments[chan->inst_nr];
|
||||
|
||||
if(chan->level > inst->decay) chan->level -= inst->decay;
|
||||
else chan->level = 0;
|
||||
|
||||
chan->pulse_width += inst->pulse_sweep;
|
||||
|
||||
chan->pos++;
|
||||
if(wave_table[chan->pos][1] == 0xff) chan->pos += wave_table[chan->pos][0];
|
||||
|
||||
|
||||
// enter new rol
|
||||
// w
|
||||
if(tick == 0) {
|
||||
uint8_t pattern_nr = pattern_table[seq][i];
|
||||
uint8_t note = pgm_read_byte(&patterns[pattern_nr][row][0]);
|
||||
|
||||
if(note) { // new note, maybe?
|
||||
if(note == 0xff) {
|
||||
chan->level = 0;
|
||||
} else {
|
||||
chan->level = 80; // TODO: less?
|
||||
chan->note = note;
|
||||
chan->inst_nr = pgm_read_byte(&patterns[pattern_nr][row][1]);
|
||||
inst = &instruments[chan->inst_nr];
|
||||
chan->pos = inst->wave_table_pos;
|
||||
if(inst->pulse_width) chan->pulse_width = inst->pulse_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(++sample == 0){
|
||||
if(++tick == row_length) {
|
||||
tick = 0;
|
||||
if(++row == pattern_length) {
|
||||
row = 0;
|
||||
if(++seq == pattern_table_length) {
|
||||
seq = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t output = 0;
|
||||
for(int i = 0; i < channel_count; i++) {
|
||||
synth_channel_t* chan = &channels[i];
|
||||
// const synth_instrument_t* inst = &instruments[chan->inst_nr];
|
||||
|
||||
chan->phase += pgm_read_word(&freq_table[(uint8_t)(chan->note + wave_table[chan->pos][0])]);
|
||||
|
||||
uint8_t amp;
|
||||
switch(wave_table[chan->pos][1]) {
|
||||
case WAVE_PULSE:
|
||||
amp = -(chan->phase < chan->pulse_width);
|
||||
break;
|
||||
|
||||
case WAVE_SAW:
|
||||
amp = (chan->phase >> 8);
|
||||
break;
|
||||
|
||||
case WAVE_NOISE: // shitty noise
|
||||
chan->phase = (chan->phase >> 1) ^ (-(chan->phase & 1) & 0xb400);
|
||||
amp = (chan->phase >> 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
amp = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
output += (((amp & 0xff) * chan->level) >> 8);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/* fill all the timeslots */
|
||||
inline void synth_poll(void) {
|
||||
/* refill timeslots queue */
|
||||
// while (timeslots_fill < (SYNTH_BUFSIZE-1))
|
||||
if (timeslots_fill < (SYNTH_BUFSIZE-1))
|
||||
enqueue_timeslot(synth_mix());
|
||||
}
|
||||
|
||||
/* timeslot queue handling */
|
||||
static inline void enqueue_timeslot(uint8_t synthval) {
|
||||
timeslots[timeslots_write & SYNTH_BUFMASK] = synthval;
|
||||
timeslots_fill++;
|
||||
timeslots_write++;
|
||||
}
|
||||
|
||||
static inline uint8_t dequeue_timeslot() {
|
||||
uint8_t t = timeslots[timeslots_read & SYNTH_BUFMASK];
|
||||
if(timeslots_fill){
|
||||
/* buffer not underrun... move forward in readbuffer */
|
||||
|
||||
timeslots_fill --;
|
||||
timeslots_read ++;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
ISR(TIMER0_COMPA_vect)
|
||||
{
|
||||
/* calculate next analog sample value in synth mixer:*/
|
||||
OCR1B = dequeue_timeslot();
|
||||
}
|
||||
|
||||
|
34
firmware/lib/synth.h
Normal file
34
firmware/lib/synth.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef SYNTH_H
|
||||
#define SYNTH_H
|
||||
|
||||
#define SYNTH_BUFSIZE (16)
|
||||
#define SYNTH_BUFMASK (0b00001111)
|
||||
|
||||
enum { WAVE_OFF, WAVE_PULSE, WAVE_SAW, WAVE_NOISE };
|
||||
|
||||
typedef struct {
|
||||
uint8_t note;
|
||||
uint8_t inst_nr;
|
||||
uint8_t pos;
|
||||
|
||||
uint16_t phase;
|
||||
uint16_t pulse_width;
|
||||
|
||||
uint8_t level; // envelop level
|
||||
|
||||
} synth_channel_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint16_t pulse_width;
|
||||
uint8_t pulse_sweep;
|
||||
uint8_t wave_table_pos;
|
||||
uint8_t decay;
|
||||
|
||||
} synth_instrument_t;
|
||||
|
||||
|
||||
void synth_init(void);
|
||||
void synth_poll(void);
|
||||
|
||||
#endif
|
136
firmware/lib/usart.c
Normal file
136
firmware/lib/usart.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* PentaFnord Firmware
|
||||
*
|
||||
* by Alexander Lorz <bigalex@gmx.de>
|
||||
*
|
||||
*
|
||||
* The USART control code is derived by code from the 4CHLED project
|
||||
* by sebseb7: https://github.com/sebseb7/eagle/tree/master/4CHLED/firmware
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
//#include "main.h"
|
||||
#include "usart.h"
|
||||
|
||||
#define UART_RXBUFSIZE 32
|
||||
|
||||
volatile static uint8_t rxbuf0[UART_RXBUFSIZE];
|
||||
volatile static uint8_t *volatile rxhead0, *volatile rxtail0;
|
||||
//volatile uint8_t xon = 0;
|
||||
|
||||
|
||||
ISR (USART_RX_vect)
|
||||
{
|
||||
UCSR0B &= ~(1 << RXCIE0);
|
||||
asm volatile("sei");
|
||||
|
||||
int diff;
|
||||
uint8_t c;
|
||||
c=UDR0;
|
||||
diff = rxhead0 - rxtail0;
|
||||
if (diff < 0) diff += UART_RXBUFSIZE;
|
||||
if (diff < UART_RXBUFSIZE -1)
|
||||
{
|
||||
*rxhead0 = c;
|
||||
++rxhead0;
|
||||
if (rxhead0 == (rxbuf0 + UART_RXBUFSIZE)) rxhead0 = rxbuf0;
|
||||
// if((diff > 100)&&(xon==0))
|
||||
// {
|
||||
// xon=1;
|
||||
// //set the CTS pin
|
||||
// }
|
||||
}
|
||||
UCSR0B |= (1 << RXCIE0);
|
||||
}
|
||||
|
||||
|
||||
void USART0_Init (void)
|
||||
{
|
||||
// set baudrate
|
||||
#undef BAUD
|
||||
#define BAUD 115200
|
||||
#include <util/setbaud.h><util/setbaud.h>
|
||||
UBRR0H = UBRRH_VALUE;
|
||||
UBRR0L = UBRRL_VALUE;
|
||||
|
||||
//#if USE_2X
|
||||
UCSR0A |= (1 << U2X0); // enable double speed operation
|
||||
//#else
|
||||
// UCSR0A &= ~(1 << U2X0); // disable double speed operation
|
||||
//#endif
|
||||
|
||||
|
||||
// flush receive buffer
|
||||
while ( UCSR0A & (1 << RXC0) ) UDR0;
|
||||
|
||||
// set 8N1
|
||||
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
|
||||
UCSR0B &= ~(1 << UCSZ02);
|
||||
|
||||
UCSR0B |= (1 << RXEN0)|(1 << TXEN0); //enable send and receive
|
||||
|
||||
UCSR0B |= (1 << RXCIE0); //enable receive interrup
|
||||
|
||||
rxhead0 = rxtail0 = rxbuf0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void USART0_putc (char c)
|
||||
{
|
||||
|
||||
loop_until_bit_is_set(UCSR0A, UDRE0);
|
||||
UDR0 = c;
|
||||
}
|
||||
|
||||
|
||||
uint8_t USART0_Getc_nb(uint8_t *c)
|
||||
{
|
||||
if (rxhead0==rxtail0) return 0;
|
||||
*c = *rxtail0;
|
||||
if (++rxtail0 == (rxbuf0 + UART_RXBUFSIZE)) rxtail0 = rxbuf0;
|
||||
|
||||
// uint8_t diff = rxhead0 - rxtail0;
|
||||
// if((diff < 10)&&(xon==1))
|
||||
// {
|
||||
// xon=0;
|
||||
// //set the CTS pin
|
||||
// }
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void USART0_crlf(){
|
||||
USART0_putc(0x0A); //newline
|
||||
USART0_putc(0x0D); //carriage return
|
||||
};
|
||||
|
||||
void USART0_put_uint8(uint8_t x){
|
||||
uint8_t highchar=((x & 0b11110000)>>4)+0x30;
|
||||
uint8_t lowchar = (x & 0b00001111)+0x30;
|
||||
highchar = highchar>0x39 ? highchar + 0x07 : highchar; //chars A to F start with 0x41 not 0x3A
|
||||
lowchar = lowchar>0x39 ? lowchar + 0x07 : lowchar;
|
||||
USART0_putc(highchar);
|
||||
USART0_putc(lowchar);
|
||||
|
||||
}
|
||||
void USART0_put_uint16(uint16_t x){
|
||||
USART0_put_uint8 ((x & 0xFF00)>>8);
|
||||
USART0_put_uint8 (x & 0x00FF);
|
||||
|
||||
}
|
34
firmware/lib/usart.h
Normal file
34
firmware/lib/usart.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* PentaFnord Firmware
|
||||
*
|
||||
* by Alexander Lorz <bigalex@gmx.de>
|
||||
*
|
||||
*
|
||||
* The USART control code is derived by code from the 4CHLED project
|
||||
* by sebseb7: https://github.com/sebseb7/eagle/tree/master/4CHLED/firmware
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program 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 General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _USART_H
|
||||
#define _USART_H
|
||||
|
||||
void USART0_Init (void);
|
||||
void USART0_putc (char c);
|
||||
uint8_t USART0_Getc_nb(uint8_t*);
|
||||
void USART0_put_uint8(uint8_t);
|
||||
void USART0_crlf();
|
||||
void USART0_put_uint16(uint16_t);
|
||||
|
||||
#endif
|
||||
|
|
@ -49,29 +49,6 @@ static inline void init_pwm(void)
|
|||
return;
|
||||
}
|
||||
|
||||
static void init_leds(void)
|
||||
{
|
||||
/* enable LED channels as output */
|
||||
DDRC |= (1 << PORTC0) | (1 << PORTC2) |
|
||||
(1 << PORTC3) | (1 << PORTC1) ;
|
||||
/* initially one led is on */
|
||||
PORTC = 0b00000101;
|
||||
|
||||
/*
|
||||
* Timer 2
|
||||
*/
|
||||
|
||||
/* set timer2 to CTC & prescaler 64 → ???125kHz increment */
|
||||
TCCR2A = (1 << WGM21);
|
||||
TCCR2B = (1 << CS20)|(1 << CS21);
|
||||
|
||||
OCR2A = 255; /* TOP */
|
||||
TCNT2 = 0;
|
||||
/*enable interrupt*/
|
||||
TIMSK2 |= (1<<OCIE2A);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
inline void setleds(uint8_t state)
|
||||
{
|
||||
|
@ -81,13 +58,6 @@ inline void setleds(uint8_t state)
|
|||
return;
|
||||
}
|
||||
|
||||
static void init_motor(void)
|
||||
{
|
||||
/* vibration motor on B1, initially off: */
|
||||
DDRB |= (1 << PORTB1);
|
||||
PORTB &= ~( 1<<PORTB1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user