Tania ATmega8 z Chin: podróbka czy okazja?
MilisecondsTimer.cpp
#include <avr/io.h>
#include <avr/interrupt.h>
#include "MillisecondTimer.h"
volatile uint32_t MillisecondTimer::_counter=0;
volatile uint8_t MillisecondTimer::_subCounter=0;
/*
* Timer 0 interrupt handler
*/
ISR(TIMER0_OVF_vect) {
MillisecondTimer::_subCounter++;
if((MillisecondTimer::_subCounter & 0x3)==0)
MillisecondTimer::_counter++;
TCNT0+=6;
}
Teraz możemy odmierzać czas. Potrzebuję prostego sposobu na adresowanie pinów GPIO. Oto efektywne rozwiązanie: szablony i definicje typów pozwalają uzyskać czytelny kod, a implementacja w czystym asemblerze zapewnia, że rozwiązanie jest maksymalnie wydajne.
GpioPin.h
#pragma once
/*
* GPIO ports
*/
struct GPIOB {
enum {
Port = 0x18,
Dir = 0x17,
Pin = 0x16
};
};
struct GPIOC {
enum {
Port = 0x15,
Dir = 0x14,
Pin = 0x13
};
};
struct GPIOD {
enum {
Port = 0x12,
Dir = 0x11,
Pin = 0x10
};
};
/*
* Base template for all GPIO pins. Provide support for set/reset
*/
template<uint8_t TPort,uint8_t TPin>
struct GpioPin {
static void set() {
asm volatile(
" sbi %[port],%[pin] \n\t"
:: [port] "I" (TPort),
[pin] "I" (TPin)
);
}
static void reset() {
asm volatile(
" cbi %[port],%[pin] \n\t"
:: [port] "I" (TPort),
[pin] "I" (TPin)
);
}
static void changeTo(bool state) {
if(state)
set();
else
reset();
}
};
/*
* GPIO output, provide support for init
*/
template<class TPort,uint8_t TPin>
struct GpioOutputPin : GpioPin<TPort::Port,TPin> {
static void setup() {
asm volatile(
" sbi %[port],%[pin] \n\t"
:: [port] "I" (TPort::Dir),
[pin] "I" (TPin)
);
}
};
/*
* GPIO input, provide support for init, read
*/
template<class TPort,uint8_t TPin>
struct GpioInputPin : GpioPin<TPort::Port,TPin> {
static void setup() {
asm volatile(
" cbi %[port],%[pin] \n\t"
:: [port] "I" (TPort::Dir),
[pin] "I" (TPin)
);
}
static bool read() {
uint8_t r;
asm volatile(
" clr %[result] \n\t" // result = 0
" sbic %[port],%[pin] \n\t" // skip next if port bit is clear
" inc %[result] \n\t" // result = 1
: [result] "=r" (r)
: [port] "I" (TPort::Pin),
[pin] "I" (TPin)
);
return r;
}
};
/*
* All pins used in this project
*/
typedef GpioOutputPin<GPIOD,5> GpioLed;
Po tych przygotowaniach napisanie funkcji main, która obsługuje miganie, jest trywialne.
Blink.cpp
#include <avr/io.h>
#include <avr/interrupt.h>
#include "GpioPin.h"
#include "MillisecondTimer.h"
int main() {
MillisecondTimer::setup();
GpioLed::setup(); // PD5 (pin 11)
sei();
for(;;) {
GpioLed::set();
MillisecondTimer::delay(1000);
GpioLed::reset();
MillisecondTimer::delay(1000);
}
// not reached
return 0;
}
Kod jest już napisany i musimy go skompilować. Wykorzystuję narzędzie scons, ponieważ jest oparte na Pythonie – języku użytecznym też w innych sytuacjach.
Oto mój plik SConstruct. Wykorzystujemy program avrdude do wgrania pliku binarnego do pamięci mikrokontrolera za pomocą programatora USBAPA, a polecenie fuse ustawia zworki na wykorzystanie zewnętrznego oscylatora.
SConstruct
"""
Usage: scons [upload]
[upload]
specify this option to automatically upload to
using avrdude to a USBASP connected MCU.
To do a 'clean' use the -c flag
To do a parallel build use the -jN flag
"""
import os
# source the environment
env=Environment(ENV=os.environ)
# compiler is avr-gcc
env.Replace(CC="avr-gcc")
env.Replace(CXX="avr-g++")
env.Replace(PROGSUFFIX=".elf")
# set up our options
env.Replace(CXXFLAGS=["-mmcu=atmega8",
"-Os",
"-g",
"-DF_CPU=8000000",
"-std=c++11",
"-Wall",
"-Werror",
"-Wextra",
"-pedantic-errors",
"-fno-rtti",
"-ffunction-sections",
"-fdata-sections",
"-fno-exceptions"])
env.Replace(LINKFLAGS=["-Wl,-Map,blink.map",
"-mrelax",
"-g",
"-Wl,--gc-sections",
"-mmcu=atmega8"])
# compile source code to .elf binary
elf=env.Program("blink",[Glob("*.cpp")])
Decider('timestamp-newer')
# convert elf to hex flashable image
env.Command("blink.hex",elf,"avr-objcopy -j .text -j .data -O ihex $SOURCE $TARGET")
# calculate size and generate assembly source
env.Command("blink.siz",elf,"avr-size $SOURCE | tee $TARGET")
env.Command("blink.lst",elf,"avr-objdump -S $SOURCE > $TARGET")
# upload target uses avrdude
flash_cmd="avrdude -c usbasp -p m8 -e -U flash:w:blink.hex"
# internal oscillator
#fuse_cmd="avrdude -c usbasp -p m8 -e -U lfuse:w:0xe4:m -U hfuse:w:0xd9:m"
# external crystal
fuse_cmd="avrdude -c usbasp -p m8 -e -U lfuse:w:0xff:m -U hfuse:w:0xd9:m"
upload=env.Alias("upload","blink.hex",flash_cmd)
fuse=env.Alias("fuse","blink.hex",fuse_cmd)
AlwaysBuild([upload,fuse])

Technologie End of Life i bezpieczeństwo sieci – wyzwania Europy związane z tzw. długiem technologicznym
Najczęstsze błędy firm przy wyborze dostawcy energii i jak ich uniknąć
Fotorezystor, czyli czujnik światła dwojakiego działania. Przykład innowacji w automatyce i elektronice możliwej dzięki technologii fotooporników 



