※Arduinoやmbedの記事ではありません。
AVRをCとアセンブラで開発、JTAGICEでデバッグ。
CPUはTiny2313・ATmega328・ATmega1284など。
ラジコンで使う比例制御方式のサーボを動かす記事があります。
AVRはArduinoに使われてますが、ここではJTAGICEと共にC言語やアセンブラで直接コーディングしています。
Mega1284PをJTAGで接続
mega1284Pを使い始めたのでメモ。
このCPUをJTAGで接続しましたが、ISP接続の数倍の速さが出るんでかなり快適です。
コンパイル終了後、最初のステップ実行まで2秒ほどで行ける。
この速さはかなり大事です。
「コンパイル → デバッグ」は開発中は数百数千回も繰り返す動作だから、この動作が速いのは開発効率に凄く響く・・・遅いと次にやることを忘れたりするし(^^;
と言うことで、もうISP接続は却下。
これからはやれる場合はコーディングは1284Pで行い、大体完成してから328P等に移植する方式で行きたい。
CPUの交換方法はこちら
これならSPIのデバッグも簡単にできる(ISP接続してるとSPI部分の実動作デバッグが出来なくて不便だった)。
それとこのCPUはPA~PD迄のポートが整然と8bit並んでて気持ち良いです。
なお5V動作の場合は外部Xtalの18.432MHz(ボーレートの絡み。ここの表を参照)を使用可能。ボーレートも115200以上も使える。
Fuse設定の注意
UARTにクロックを供給する為には外部Xtalをフルスイング動作させる必要が有る。
フルスイング動作電圧2.7~5.5V。
3Vでは10MHz迄しか動かないので、内蔵8MhzOSCを使い、UARTのボーレートの最高速度は38400としてる。
外部Xtal使用時のFuse設定。詳細はこちら
内蔵OSC使用時のFuse設定
//F_CPU定義
#ifndef _COMMON_H_
#define _COMMON_H_
// F_CPU指定(Fuseを合わせる)
#define F_CPU 18432000UL // 外部Xtalの18.432MHz
//#define F_CPU 8000000UL // 内蔵OSCの8.000MHz
//UARTの定義部分
// バッファサイズ:328はRAM=2K,1284はRAM=16Kだ
#define FIFO_SIZE 64
// ボーレート:F_CPU=8MHz時は38400,18.432Mhzなら230400まで行ける
#if F_CPU == 8000000UL
#define BAUD 38400
#warning "ボーレートは38400だ in _uart.c"
#elif F_CPU == 18432000UL
#define BAUD 115200
#warning "ボーレートは115200だ in _uart.c"
#else
#warning "F_CPU指定が変だよ in _uart.c"
#endif
// 1284はUART0を使用
#if defined (__AVR_ATmega1284P__)
#define _ISR_RX_NAME USART0_RX_vect // 受信割込みベクタ
#define _ISR_UDRE_NAME USART0_UDRE_vect // 送信 "
#warning "UARTは1284p用に作成された in _uart.c"
// 328はUARTは一つだけだ
#elif defined (__AVR_ATmega328P__)
#define _ISR_RX_NAME USART_RX_vect // 受信割込みベクタ
#define _ISR_UDRE_NAME USART_UDRE_vect // 送信 "
#warning "UARTは328p用に作成された in _uart.c"
#endif
5V動作時:消費電流はUARTで通信する程度なら15mA程
・電源はTTL_232R_5V(Max75mA)からの出力。
・外部Xtal使用
・UARTのボーレートは230400以下
3V動作時:消費電流はUARTで通信する程度なら8mA程
・電源はTTL_232R_3V3(Max75mA)、またはFT232RL(Max24mA)からの出力。
・内蔵OSC使用
・UARTのボーレートは38400以下
その他
・抵抗入りLEDの消費電流は4mA
Timer0でインターバル割込み
Timer1は16bitで、今後なにかと使い途があるので、インターバル割込み程度は8bitのTimer0で。
使ったCPUはmega1284Pだけど、328P(分周比設定レジスタTCCR0BのCS0/1/2が5段階タイプ)も使えるはず。
能書きはここが簡潔で詳しいです。ここも。
タイマーは結構面倒くさい部分が多いんだけど、AVRのは割と簡単。
クロックソースは外部Xtalの18.432MHzと、内蔵OSCの8MHzを #if で切り換える方式。
PA0にオシロを繋いでインターバルを見ながら作った。使ってるオシロはこれ。
この手のパソコンオシロは画面を取り込みやすくて良いですね。
ヘッダファイル “atmega164p_354p_644p_mori2.5.0.h” は、ルネサス方式のレジスタ指定を可能にするファイルで、森下功啓製作所さんで頂いたこれ・・・便利に使わせて頂いております。有り難うございます。
この頃シミジミ思うけど、みなさん親切でホント助かってます。
//Timer0による割込み
#include "_common.h"
#include "_typedefs.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/sfr_defs.h>
#include <avr/power.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "_prototype.h"
#include "atmega164p_354p_644p_mori2.5.0.h"
static volatile CALLBACK_FUNC _cbfunc=0;
static volatile CALLBACK_FUNC _dpcfunc = 0;
static volatile ulong _dpctm = 0;
//==========================================================================================================
// timer0の初期化
// TCCR0Bで分周比を設定する:000=停止,001=分周ナシ,010=8,011=64,100=256,101=1024
// OCR0Aでカウント個数を設定する
//==========================================================================================================
void timer0_init(CALLBACK_FUNC func)
{
_cbfunc=func; // コールバック関数設定
TCCR0B = 0b00000000; // 停止させてから設定する
TCCR0A = 0b00000010; // CTC動作
TIMSK0 = 0b0000010; // 比較A一致割り込み有効
//------------------------------
// φ18.432MHzの場合
//------------------------------
#if F_CPU == 18432000UL
// 1mSのインターバルの場合
TCCR0B = 0b00000100; // 100=256分周
OCR0A = 71; // 0.001秒 / (1 / 18432000 * 256分周) = 72(71設定時1.00mS)
// 100uSのインターバルの場合
//TCCR0B = 0b00000010; // 010=8分周
//OCR0A = 230; // 0.0001秒 / (1 / 18432000 * 8分周) = 230.4(230設定時100.26uS)
//------------------------------
// φ8.000MHzの場合
//------------------------------
#elif F_CPU == 8000000UL
// 1mSのインターバルの場合
TCCR0B = 0b00000011; // 011=64分周
OCR0A = 124; // 0.001秒 / (1 / 8000000 * 64分周) = 125(124設定時1.00mS)
// 100uSのインターバルの場合
//TCCR0B = 0b00000010; // 010=8分周
//OCR0A = 99; // 0.0001秒 / (1 / 8000000 * 8分周) = 100.0(99設定時100.00uS)
#else
#warning "F_CPUエラー in _timer0.c"
#endif
PA.DDR.BIT.B0 = 1; // for debug PA0=OUT
}
//---------------------------------------------------------------------------------------------------
// Timer0 ISR
//---------------------------------------------------------------------------------------------------
ISR(TIMER0_COMPA_vect)
{
PA.PIN.BIT.B0 = 1; // for debug PA0=bit反転
// インターバル毎に登録された関数を呼出す
if (_cbfunc) _cbfunc();
// DPC処理
if (_dpcfunc && _dpctm) {
if (0 == --_dpctm) _dpcfunc();
}
}
//===================================================================================================
// Deferred Procedure Call:指定時間経過時に実行する関数を登録する
//===================================================================================================
void timer0_dpcr(CALLBACK_FUNC func, ulong tcnt)
{
_dpcfunc = func;
_dpctm = tcnt;
}
Timer0とTimer2によるハードウエアPWM
ラジコンのサーボを動かしたり、LEDの明るさ調節なんかに使うハードウエアPWM。
周波数が低くて構わないならインターバル割込みでソフト的にPWMする手も有る。
ヘッダファイル “atmega164p_354p_644p_mori2.5.0.h” はこちらに記述。
//----------------------------------------------------------------------------------------------------------/*
* _pwm.c
*
* Created: 平成 24/8/3 5:10:21
* Author: oj3
* 2013/11/09 機能追加
*
* <注意>
* timer0/2を使ったハードウエアPWM(mylib.cにはtimer0割込みによるソフトPWMがあるよ)
* ここでtimer0を使うと_timer0.cのインターバルタイマは使えなくなる
*
* <解説>
* timer0/2は8bitカウンタのタイマーだ(timer1は16bitでインプットキャプチャ可)。
* timer0は外部φを入力可、timer2は内部φのみだけど分周比を細かく設定できる・・・違いはここだけ。
* なおどちらも8bitカウンタなので、出力される周波数は "CPUφ÷256÷分周値"となる。
*
* <他>
* ラジコンサーボを動かす場合は、timer一個で2CH分を動かすことが可能。
* つまりOCxAとOCxBには同じ周波数で異なるdutyを出すことができる。
* // duty値:15=1.03mS, 22=1.47mS, 31=1.99mS
* OCRxA = 22; // CH1用のduty:1.47mS幅
* OCRxB = 15; // CH2 " :1.03mS幅
* なお16MHzを1024分周すれば手頃な周波数になるよ(16MHz÷256÷1024=周期16mS)
*
* <参照先>
* http://startelc.com/AVR/Avr_100timrMemo.html
* https://sites.google.com/site/hananekosugan/sanpuru-kodo/avr-basic-usage-sample-code/fastpwm
* http://usicolog.nomaki.jp/engineering/avr/avrPWM.html
* http://www.natural-science.or.jp/article/20101223202536.php
*///----------------------------------------------------------------------------------------------------------
#include "_common.h"
#include "_typedefs.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/sfr_defs.h>
#include <string.h>
#include <stdlib.h>
#include "atmega164p_354p_644p_mori2.5.0.h"
#define _TIMER0_USE 0 // timer0をPWMとして使うなら1(_timer0.cのインターバルタイマは使えなくなるよ)
#define _TIMER2_USE 1 // timer2 "
//==========================================================================================================
// 初期化
//==========================================================================================================
void pwm_init(int usetimer)
{
#if _TIMER0_USE == 1
//-------------------------------------------------------------------
// 8bitのtimer0によるPWM周波数の設定(timer2と異なり外部φも使える)
//-------------------------------------------------------------------
#if defined (__AVR_ATmega1284P__)
PB.DDR.BIT.B3 = 1; // PB3(OC0A)=OUT
PB.DDR.BIT.B4 = 1; // PB4(OC0B)=OUT
#elif defined (__AVR_ATmega328P__)
PD.DDR.BIT.B6 = 1; // PD6(OC0A)=OUT
PD.DDR.BIT.B5 = 1; // PD5(OC0B)=OUT
#endif
TCCR0A = 0b10100011; // OC0A=PWM出力,OC0B=PWM出力,高速PWM&非反転動作
TCCR0B = 0b00000011; // 000=停止,001=分周ナシ,010=8,011=64,100=256,101=1024,110&111=外部φ
#endif
#if _TIMER2_USE == 1
//-------------------------------------------------------------------
// 8bitのtimer2によるPWM周波数の設定(timer0よりも分周比を細かく設定できる)
//-------------------------------------------------------------------
#if defined (__AVR_ATmega1284P__)
PD.DDR.BIT.B7 = 1; // PD7(OC2A)=OUT
PD.DDR.BIT.B6 = 1; // PD6(OC2B)=OUT
#elif defined (__AVR_ATmega328P__)
PB.DDR.BIT.B3 = 1; // PB3(OC2A)=OUT
PD.DDR.BIT.B3 = 1; // PD3(OC2B)=OUT
#endif
TCCR2A = 0b10100011; // OC2A=PWM出力,OC2B=PWM出力,高速PWM&非反転動作
TCCR2B = 0b00000100; // 000=停止,001=分周ナシ,010=8,011=32,100=64,101=128,110=256,111=1024
#endif
}
//==========================================================================================================
// dutyのセット(1~255)
// OCxAとOCxBには同一周波数で異なるdutyのPWM波形を出力可
//==========================================================================================================
void pwm_duty0(uint8_t a, uint8_t b) // Timer0
{
#if _TIMER0_USE == 1
OCR0A = a;
OCR0B = b;
#else
while (1); // timer0未使用時はstop
#endif
}
void pwm_duty2(uint8_t a, uint8_t b) // Timer2
{
#if _TIMER2_USE == 1
OCR2A = a;
OCR2B = b;
#else
while (1); // timer2未使用時はstop
#endif
}
インターバル割込みを使ったソフトウエアPWM
周波数が低くて構わないのならインターバル割込みでソフト的にPWMする。
ここではPBにPWMを出力してる。
タイマー割込みのインターバルが1mSならPWM周波数は1KHzになるが、LEDの明るさ調節程度ならこれで十分。
またdutyは0~10で指定している(0=消灯)。
//===================================================================================================
// ソフトPWMで点灯する
//===================================================================================================
static BYTE _cp, _ch;
void mylib_softPwmSet(BYTE usebit, BYTE lum)
{
_ch = usebit; // 点灯するBIT
_cp = lum; // 明るさ(0~10)
}
// PWM動作(1mS毎のインターバルタイマ割込みで実行される)
static void _softPwmIntr(void)
{
static BYTE c;
static bool onoff;
if (++c == 10) c = 0;
// 点灯
if (c < _cp) {
if (onoff == OFF) {
onoff = ON;
PORTB = _ch; // Hで点灯
}
}
// 消灯
else {
if (onoff == ON) {
onoff = OFF;
PORTB = 0; // Lで消灯
}
}
}
Mega1284PのSPIでIOを増やす
この記事はアホ丸出しです。
こんなことをしなくてもLPC1768かLPC1114のQFPパッケージを使うとか、IOエキスパンダでも良いし。
世間知らずは恐ろしいことを始めます(爆)
多数のIOが必要な場合は、今では素直にmbedを使ってます。
mbedを使って新規製品のプロトタイプを作ってるんだけど、I/Oが不足してきた。
もう一個mbedを足しても良いんだけど、将来もっともっとI/Oを増やすことを考えると、ここはAVRでしょ!・・・そんなに増えることなんて無いって(笑)
で、mega1284Pの出番。
これはJTAGが使えるのでやっぱり便利。
mbedとはSPIで接続した。
通信速度は1MHz、MODE=3。
1284Pを最高速度で動作させるには仕様上は5Vが必要です・・・3.3Vでも動いてる感じはしますが・・・
mbedはSPIのmaster(マスター)、mega1284PはSPIのslave(スレーブ)。
mbedからSPIでコマンドを出力し、受け取った1284PはポートにOUTしたり、PORTからINした値をmbedに返したりする。
最初はUARTでやってたんだけど、拡張性を考えるとやっぱりSPIだろってことで。
I2Cでも良いんだけど、今回はSPI接続の周辺が他にあるんでSPIにした。
回路はこんな感じで・・・ごく当たり前に繋いだだけです。
プロトコルと言うほどの物じゃないけど、念のため通信用のヘッダを付けることにした。
1パケットは ヘッダ(0xff)+PORT+DATA。
1284PのポートからINするときはPORTのBIT7を立てる、OUTするときは0のまま。
またDATA=0xffの時はヘッダと区別がつかなくなるんで、PORTのBIT6を立てることにした。
mbed側のソフトはこれ(省略有り)。
ちょい無駄なコードも入ってます。
// SPI
SPI SPI_a(p5, p6, p7); // mosi, miso, sck
DigitalOut DGO_VoiceSs(p21); // Voice ss
DigitalOut DGO_M1284Ss(p8); // M1284 ss
DigitalOut DGO_Fpga1Ss(p13); // FPGA-1 ss
DigitalOut DGO_Fpga2Ss(p14); // FPGA-2 ss
// mainで初期設定しておく
SPI_a.format(8, 3); // 8bit,mode=3
SPI_a.frequency(1000000); // clk=1MHz
//----------------------------------------------------------------------------------------
// Mega1284Pとの通信
//----------------------------------------------------------------------------------------
// M1284へOUTする(port指定はPA=0/PB=1/PC=2/PD=3)
static void AvrOut(int port, BYTE data)
{
if (data == 0xff) {
port |= BIT6;
data = 0;
}
DGO_M1284Ss = 0;
SPI_a.write(0xff); // header send
SPI_a.write(port); // port send
SPI_a.write(data); // data send
DGO_M1284Ss = 1;
}
// M1284からINする(port指定はPA=0/PB=1/PC=2/PD=3)
static BYTE AvrIn(int port)
{
DGO_M1284Ss = 0;
wait_us(2); // Slaveが準備出来るまでチョイ待つ
SPI_a.write(0xff); // header send
SPI_a.write(port|BIT7); // port send
SPI_a.write(0); // data send
wait_us(5); // Slaveが転送中にSSをDisableにしないようにチョイ待つ
DGO_M1284Ss = 1;
DGO_M1284Ss = 0;
wait_us(2); // Slaveが準備出来るまでチョイ待つ
while (SPI_a.write(0) != 0xff); // header recv
port = SPI_a.write(0); // port recv
BYTE data = SPI_a.write(0); // data recv
wait_us(5); // Slaveが転送中にSSをDisableにしないようにチョイ待つ
DGO_M1284Ss = 1;
if (port & BIT6) data = 0xff;
return data;
}
mega1284Pのソースはこれ。
こっちは「部品としての動き」が必要なんでWDTを使用。
ヘタなタイムアウトのコードを入れるよりも、WDTの方がずっと安全。
なおWDTに関してはこちらとこちらを参照させて頂いた。有り難うございます。
//----------------------------------------------------------------------------------------
//
// SPI_IO 2013/12/07 oj3 mbedとMega1284PとのSPI(MODE=3)通信によるI/O
// ・m1284はSlaveとして動作する(内蔵φ8Mで使用)
// ・timeoutはWDTを使用(ヘッダ受信後に残りのデータは250mS以内に受信終了すること)
//
// mbed → 1284
// [0]:ヘッダ(FFh)
// [1]:ポートアドレスなど
// bit7 :I/O方向の指定で0=OUT, 1=IN
// bit6 :1ならOUT値はFFh
// bit5~2:予備
// bit1~0:ポートアドレス(PA=0,PB=1,PC=2,PD=3)
// [2]:ポートへのOUT値
// 0~FEh(FFhをOUTする時はDontCare)
//
// 1284 → mbed
// [0]:ヘッダ(FFh)
// [1]:ポートアドレスなど
// bit7 :DontCare
// bit6 :1ならIN値はFFh
// bit5~2:予備
// bit1~0:ポートアドレス(PA=0,PB=1,PC=2,PD=3)
// [2]:IN値
// 0~FEh(FFhをINした時はDontCare)
//
//----------------------------------------------------------------------------------------
#define _MAIN
#include "_common.h"
#include "_typedefs.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/sfr_defs.h>
#include <avr/power.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "_prototype.h"
#include "atmega164p_354p_644p_mori2.5.0.h"
#define _WDT_15MS ((0<<WDP3)|(0<<WDP2)|(0<<WDP1)|(0<<WDP0))
#define _WDT_30MS ((0<<WDP3)|(0<<WDP2)|(0<<WDP1)|(1<<WDP0))
#define _WDT_60MS ((0<<WDP3)|(0<<WDP2)|(1<<WDP1)|(0<<WDP0))
#define _WDT_120MS ((0<<WDP3)|(0<<WDP2)|(1<<WDP1)|(1<<WDP0))
#define _WDT_250MS ((0<<WDP3)|(1<<WDP2)|(0<<WDP1)|(0<<WDP0))
#define _WDT_500MS ((0<<WDP3)|(1<<WDP2)|(0<<WDP1)|(1<<WDP0))
#define _WDT_1S ((0<<WDP3)|(1<<WDP2)|(1<<WDP1)|(0<<WDP0))
#define _WDT_2S ((0<<WDP3)|(1<<WDP2)|(1<<WDP1)|(1<<WDP0))
#define _WDT_4S ((1<<WDP3)|(0<<WDP2)|(0<<WDP1)|(0<<WDP0))
#define _WDT_8S ((1<<WDP3)|(0<<WDP2)|(0<<WDP1)|(1<<WDP0))
//----------------------------------------------------------------------------------------------------------
// SPI初期化
//----------------------------------------------------------------------------------------------------------
static void spi_init(void)
{
//-------------------------------------------------------
// SPI設定(MODE=3の場合)
// ・MSB=first
// ・SCK=アイドル状態の時Hレベル(CPOL=1)
// ・データのサンプリングはSCKの立下りで行われる(CPHA=1)
// ・SPI周波数は1MHzにしてるがSlaveなので無関係だ
//-------------------------------------------------------
SPCR = 0b01001101; // b7=0:SPIF(転送終了時)の割込みは使わない
// b6=1:SPIを使う
// b5=0:MSB first
// b4=0:slave mode
// b3=1:CPOL(クロックの向き)0=常時L, 1=常時H
// b2=1:CPHA(サンプルエッジ)0=前, 1=後ろ
// b1/0=01:分周比はfosc/16(SPI2X=1なので倍速モードでfosc/8)
// SPI2X=0 & 00=4, 01=16, 10=64, 11=128
sbi(SPSR, SPI2X); // SPI2X=1 & 00=2, 01=8 , 10=32, 11=64 → '101'=8分周=CPUφ8MHz÷8=1MHz
}
//==========================================================================================================
// main
//==========================================================================================================
int main(void)
{
cli();
// PBポートのI/O方向の設定
DDRB = 0b01000000; // PB7=IN SCK
// PB6=OUT MISO
// PB5=IN MOSI
// PB4=IN SS
// PB3=IN エンコーダPUSHSW(Push時L)
// PB2=IN DIPSW(On=L)
// PB1=IN モード選択SW(dontCare)
// PB0=IN 検査開始SW(Push時L)
// PB3/2/1/0をPullUp
// SPIで使うPB7/5/4はPulUp禁止である(PullUpすると他のデバイスがSPI信号を拾えなくなる)
// IN方向のポートに1をOUTするとPullUpしてしまうので注意せよ
PORTB = 0b00001111;
// PAポートのI/O方向の設定
DDRA = 0b11111111; // PA7~0=OUT LED付きSWのLED表示制御(Lで点灯)
// PDポートのI/O方向の設定
DDRD = 0b00000000; // PD7~0=IN LED付きSWのSW入力(Push時L)
PORTD = 0b11111111; // PD7~0 PullUp
// PCポートのI/O方向の設定
DDRC |= 0b11000011; // PC7=OUT 検査モード中LED(Lで点灯)
// PC6=OUT 登録モード中LED(Lで点灯)
// PC5~2 JTAG
// PC1=OUT 検査結果LED赤(Lで点灯)
// PC0=OUT 検査結果LED緑(Lで点灯)
// SPI設定
spi_init();
// WDT設定(250MS)
wdt_reset();
MCUSR &= ~(1<<WDRF); // 「WDTリセットされた」フラグクリア
WDTCSR |= (1<<WDCE)|(1<<WDE); // wdt変更前処理
WDTCSR = (1<<WDIE)|(1<<WDE)|_WDT_250MS;
sei();
// Loop(SS/SCIF割込みを使わずにLoopで動作)
while (1) {
while(!(SPSR & (1<<SPIF))) wdt_reset(); // header待ち(WDTクリア)
if (SPDR != 0xff) continue;
while(!(SPSR & (1<<SPIF))); // port
BYTE port = SPDR;
while(!(SPSR & (1<<SPIF))); // data
BYTE data = SPDR;
//---------------------------------
// INなら・・・
//---------------------------------
if (port & BIT7) {
port &= 0x3;
switch (port) {
case 0: data = PINA; break; // PA
case 1: data = PINB; break; // PB
case 2: data = PINC; break; // PC
case 3: data = PIND; break; // PD
}
// IN値がFFhならPORTのBIT6を立てる
if (data == 0xff) {
port |= BIT6;
data = 0x00;
}
SPDR = 0xff; // header send
while(!(SPSR & (1<<SPIF)));
SPDR = port; // port send
while(!(SPSR & (1<<SPIF)));
SPDR = data; // data send
while(!(SPSR & (1<<SPIF)));
SPDR = 0; // clear SPIF
}
//---------------------------------
// OUTなら・・・
//---------------------------------
else {
// PORTのBIT6が立ってるならOUT値はFFhだ
if (port & BIT6) data = 0xff;
port &= 0x3;
switch (port) {
case 0: PORTA = data; break; // PA
case 1: PORTB = data & 0xf; break; // PBは上位4bitがSPI用なので1をOUTしない
case 2: PORTC = data; break; // PC
case 3: PORTD = data; break; // PD
}
}
}
}
動作の確認にLAP-C(プロトコルアナライザ)を使った。設定。
mbed、AVR、LAP-C、パソコンオシロ・・・安くて良い物を売ってます。
有り難い。
CPUの交換方法
ATmega1284Pは高速でバッグが可能なJTAGを使用可能。
そこで1284pでコードを作ってから、328pにCPUを入れ替える方式で開発してる。
この場合のCPUの変更方法。
プロジェクトメニューでデバイスを328pに変更
ToolタブのICEのインターフェースを”debugWIRE”に変更(ISPではICE動作不可)
これだけで 1284p → 328p へと変更できます。
コメント