ATtiny13を使用したプログラマブル・ディバイダ

提供: 泣かないでゆり子
移動先: 案内検索
ブレッドボードに実装して開発.左からCD4046B(VCO)、ATtiny13(本ディバイダ)、AT90S2313(未使用)、DIPスイッチ(分周比設定)、謎の7セグメント。
ディバイダの入出力波形。上から入力波形、出力波形(10μS/DIV)、その下は拡大(遅延掃引、2 μS/DIV)、垂直軸感度は5V/DIV。
周波数カウンタで測った分周比。DIPスイッチを7に合わせた時のもの。1/70ピッタリ♡
回路図

PLL ICの4046で周波数シンセサイザを作ろうと思って、その前フリとしてATtiny13内蔵のカウンタでプログラマブル・ディバイダ(1/Nディバイダ)を作ってみた♡ DIPスイッチで分周比Nを設定できちゃう~♪

マイコンのI/Oポート数が少ないせいで、4bitDIPスイッチのうち3bit(0~7)しか読めない・・・RESETピンをI/Oポートにすれば4bit読めるけどISP書き込みができなくなる・・・

C言語コード

今まで(キッチンタイマーもどきなど)はアセンブラでAVRマイコンの開発を行っていたが、今回は初めてCコンパイラを用いて開発してみた。アセンブラに比べてとっても簡単☆ コンパイラ様様です。

ヒューズビット設定

HIGH: 0xFD LOW: 0x7A
SPIEN *
BODLEVEL 1V8
SUT_CKSEL INTRCOSC_9MHZ6_14CK_64MS

T0ピンパルス入力はエッジ検出回路を通りカウンタへ入力される。が、エッジ検出回路はClkI/O(I/Oクロック、ClkCPUと同じ)で駆動されているためサンプリング定理より(ClkI/O)/2 [Hz]が最高入力周波数となる。データシートによれば(ClkI/O)/2.5 [Hz]以下を推奨とのこと。消費電力が増えるが最高入力周波数を上げるため、内蔵9.6MHz発振器をClkCPUClkI/Oとした。

コード

/*
 * DeviderCounter.c
 *
 * Created: 2016/02/11 1:00:41
 *  Author: 市川ゆり子
 */ 

/*
Programmable Divider by tiny13 + DIP SW

--Fuses--
HIGH: 0xFD LOW:0x7A
SPIEN *
BODLEVEL 1V8
SUT_CKSEL INTRCOSC_9MHZ6_14CK_64MS

--PIN Connection--
1 RESET: N/C
2 PB3:   DIP SW bit 2
3 PB4:   DIP SW bit 4
4 GND:   GND
5 OC0A:  Divider signal out
6 PB1:   DIP SW bit 1
7 T0:    Divider signal in
8 Vcc:   +5V
*/

#include <avr/io.h>

char readDIPsw();
unsigned char calcOCR0AfromN(unsigned int n);

int main(void)
{
	//Peripheral initialize.
	DDRB  = 0b00100001;	//DDRB0,5 is out. other is in.
	PORTB = 0b00011010; //PORTB1,3.4 pull up.
	
	OCR0A = (unsigned int) 0;	//init Counter Compare Register
	TCCR0A = (1 << COM0A0) + (1 << WGM01);	//OC0A pin Toggle, CTC counter mode.
	TCCR0B = (1 << CS01) + (1 << CS02);		//Counter clock source T0 pin falling edge (external).

    while(1)
    {
		OCR0A = calcOCR0AfromN( 10 * readDIPsw());	//Read DIP SW and set it to Compare Register.
    }
}

//Read DIP SW state and return it.
char readDIPsw() {
	char bit0 = ~(PINB >> PINB1) & 0x01; //Read PINB1 state.
	char bit1 = ~(PINB >> PINB3) & 0x01; //Read PINB3
	char bit2 = ~(PINB >> PINB4) & 0x01; //Read PINB4
	
	return (bit2 << 2) | (bit1 << 1) | bit0;	//Joining bits.
}

// If you want set 10 to divider N, then OCR0A needs set 4.
// If N is 20, then OCR0A needs 9.
// This function calcurate OCR0A from N automatically.
unsigned char calcOCR0AfromN(unsigned int n) {
	unsigned char ocrna = (n/2) -1;
	
	if (ocrna < 0 || n == 0) {
		return 0;
	}
	
	return ocrna;
}