Skip to content

Instantly share code, notes, and snippets.

@akira345
Last active July 8, 2025 06:46
Show Gist options
  • Select an option

  • Save akira345/244e0005b12bad0b8fcba5b9afec6905 to your computer and use it in GitHub Desktop.

Select an option

Save akira345/244e0005b12bad0b8fcba5b9afec6905 to your computer and use it in GitHub Desktop.
#define F_CPU 8000000UL // 内蔵クロック8MHz
#include <avr/io.h>
#include <util/delay.h>
// 設定
#define FREQ_HZ 60 // 周波数60Hz
#define CYCLE_US (1000000UL / ((FREQ_HZ -10) * 2)) // 周期のマイクロ秒。10Hz高く出るので引く
#define HALF_PERIOD_US (CYCLE_US / 2) // 半周期のマイクロ秒
#define DEADTIME_US 20 // デッドタイム20us
#define MAX_ON_TIME_US (HALF_PERIOD_US - DEADTIME_US) // 最大ON時間(半周期からデッドタイムを引いた値)
#define START_DUTY_RATIO 0.1 // スタート時のデューティ比(10%)
#define DUTY_STEP (MAX_ON_TIME_US / 50) // デューティ比のステップ(最大ON時間の1/50)
// 出力ピン(PB0: Q1 P-ch、PB1: Q2 N-ch、PB2: Q3 P-ch、PB3: Q4 N-ch)
#define Q1_PCH_PIN PB0
#define Q2_NCH_PIN PB1
#define Q3_PCH_PIN PB2
#define Q4_NCH_PIN PB3
/*
ATTinyのPB0 → Q1(左上P-ch)のゲート(1kΩ抵抗を介して)10Kプルアップ
ATTinyのPB1 → Q2(左下N-ch)のゲート(1kΩ抵抗を介して)10Kプルダウン
ATTinyのPB2 → Q3(右上P-ch)のゲート(1kΩ抵抗を介して)10Kプルアップ
ATTinyのPB3 → Q4(右下N-ch)のゲート(1kΩ抵抗を介して)10Kプルダウン
Pchのゲートは10Kでプルアップ。Nchのゲートは10Kでプルダウン。
MOSのゲート抵抗は1kΩを介して接続。すべてトランジスタによるレベルシフトを行う。
*/
// 可変usディレイ関数
void variable_delay_us(uint16_t us) {
while (us--) {
_delay_us(1);
}
}
int main(void) {
// 出力設定
DDRB |= (1 << Q1_PCH_PIN) | (1 << Q2_NCH_PIN) | (1 << Q3_PCH_PIN) | (1 << Q4_NCH_PIN);
// 初期化
uint16_t on_time_us = MAX_ON_TIME_US * START_DUTY_RATIO;
// 全ゲートOFF(全MOSFET OFF)
PORTB = (0 << Q1_PCH_PIN) | (1 << Q2_NCH_PIN) | (0 << Q3_PCH_PIN) | (1 << Q4_NCH_PIN); // pChMOS=0(OFF), nChMOS=1(OFF)
while (1) {
// --- 左回転: Q1(P-ch,PB0)・Q4(N-ch,PB3) ON(対角のみON) ---
PORTB = (1 << Q1_PCH_PIN) | (1 << Q2_NCH_PIN) | (0 << Q3_PCH_PIN) | (0 << Q4_NCH_PIN); // Q1=1(ON), Q2=1(OFF), Q3=0(OFF), Q4=0(ON)
variable_delay_us(on_time_us);
// 全OFF(デッドタイム)
PORTB = (0 << Q1_PCH_PIN) | (1 << Q2_NCH_PIN) | (0 << Q3_PCH_PIN) | (1 << Q4_NCH_PIN); // 全OFF
variable_delay_us(DEADTIME_US);
// --- 右回転: Q3(P-ch,PB2)・Q2(N-ch,PB1) ON(対角のみON) ---
PORTB = (0 << Q1_PCH_PIN) | (0 << Q2_NCH_PIN) | (1 << Q3_PCH_PIN) | (1 << Q4_NCH_PIN); // Q1=0(OFF), Q2=0(ON), Q3=1(ON), Q4=1(OFF)
variable_delay_us(on_time_us);
// 全OFF(デッドタイム)
PORTB = (0 << Q1_PCH_PIN) | (1 << Q2_NCH_PIN) | (0 << Q3_PCH_PIN) | (1 << Q4_NCH_PIN); // 全OFF
variable_delay_us(DEADTIME_US);
// --- ソフトスタート ---
if (on_time_us < MAX_ON_TIME_US) {
on_time_us += DUTY_STEP;
if (on_time_us > MAX_ON_TIME_US) {
on_time_us = MAX_ON_TIME_US;
}
}
}
}
/*
* ATtiny85 SPWM インバーター (IR2302 x2 フルブリッジ構成)
*
* ピンアサイン:
* PB0 (pin 5) - PB0 PWM出力 (左レグ - IR2302#1のIN)
* PB1 (pin 6) - PB1 PWM出力 (右レグ - IR2302#2のIN)
* PB2 (pin 7) - PB2 : シャットダウン制御 (両IR2302のSD端子)
* PB3 (pin 2) - 未使用
* PB4 (pin 3) - 未使用
* PB5 (pin 1) - RESET
* VCC (pin 8) - 電源 +5V
* GND (pin 4) - 電源 GND
*
* フルブリッジ動作:
* - 正の半波: 左レグ上側PWM制御、右レグ下側常時ON
* - 負の半波: 右レグ上側PWM制御、左レグ下側常時ON
* - IR2302動作: IN=HIGH→上側MOSFET導通、IN=LOW→下側MOSFET導通
* - PWM周波数: 約31kHz, 正弦波周波数: 約60Hz
*/
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#define SD_PIN PB2
volatile uint8_t num = 0;
#define STEPS 160
const uint8_t sine_table[STEPS] PROGMEM = {
128, 133, 138, 143, 148, 153, 158, 162,
167, 172, 177, 181, 186, 190, 194, 199,
203, 207, 210, 214, 218, 221, 225, 228,
231, 234, 236, 239, 241, 243, 245, 247,
249, 250, 251, 253, 253, 254, 255, 255,
255, 255, 255, 254, 253, 253, 251, 250,
249, 247, 245, 243, 241, 239, 236, 234,
231, 228, 225, 221, 218, 214, 210, 207,
203, 199, 194, 190, 186, 181, 177, 172,
167, 162, 158, 153, 148, 143, 138, 133,
128, 123, 118, 113, 108, 103, 98, 94,
89, 84, 79, 75, 70, 66, 62, 57,
53, 49, 46, 42, 38, 35, 31, 28,
25, 22, 20, 17, 15, 13, 11, 9,
7, 6, 5, 3, 3, 2, 1, 1,
1, 1, 1, 2, 3, 3, 5, 6,
7, 9, 11, 13, 15, 17, 20, 22,
25, 28, 31, 35, 38, 42, 46, 49,
53, 57, 62, 66, 70, 75, 79, 84,
89, 94, 98, 103, 108, 113, 118, 123,
};
int main(void) {
cli(); // 割り込み禁止
_delay_ms(10); // 電源安定化待ち
// PWM設定(Timer0)
// PWM周波数約31.25kHz
// OCR0A(PB0)とOCR0B(PB1)を使用して、左レグと右レグのPWM出力を制御
// 8ビット高速PWM動作(WGM01, WGM00ビットを設定)
TCCR0A = (1 << COM0A1) | (1 << COM0B1) | (1 << WGM01) | (1 << WGM00); // Fast PWM, 非反転出力
TCCR0B = (1 << CS00); // 分周なし → 約31.25kHz
// PB0とPB1のPWM出力を初期化
OCR0A = 0;
OCR0B = 0;
// Timer1設定(CTCモード、分周8)
// 正弦波生成のための設定
TCCR1 = (1 << CTC1) | (1 << CS12); // 分周8
// 60Hz正弦波のために調整
// 60Hzの周期16.67ms。これを160ステップで分割すると、1ステップあたり約104us。
// 8MHzクロックの場合8MHz / 8 = 1MHz → 1us/ステップ
OCR1A = 104; // 約104us → 60Hz正弦波
OCR1C = 104; // 同じ値
TIMSK |= (1 << OCIE1A); // OCR1Aマッチ割り込み有効
// 出力ピン設定
DDRB |= (1 << PB0) | (1 << PB1) | (1 << SD_PIN);
PORTB |= (1 << SD_PIN); // IOR2302シャットダウン解除
_delay_ms(10); // IR2302起動後の安定化待ち
sei(); // 割り込み許可
while (1) {
// メインループ不要(全て割り込み駆動)
}
}
// Timer1のOCR1Aマッチ割り込みハンドラ
// 正弦波のサンプル値を読み出し、PWM出力を更新
// ここでは、sine_tableから値を読み出し、OCR0AとOCR0Bに設定します。
// numは現在のサンプルインデックスで、STEPSは正弦波テーブルのサイズです。
ISR(TIMER1_COMPA_vect) {
uint8_t value = pgm_read_byte(&sine_table[num]);
OCR0A = value; // 左レグのPWM値
OCR0B = pgm_read_byte(&sine_table[(num + STEPS/2) % STEPS]); // 反対側のレグのPWM値
num++;
if(num >= STEPS) num = 0;
}
import math
# パラメータ
STEPS = 160
AMPLITUDE = 127 # 0〜255の中心を128とする
OFFSET = 128
# テーブル生成
table = []
for i in range(STEPS):
angle = 2 * math.pi * i / STEPS
value = int(round(OFFSET + AMPLITUDE * math.sin(angle)))
table.append(value)
# Cコード形式で出力
print('#include <avr/pgmspace.h>')
print(f'const uint8_t sine_table[{STEPS}] PROGMEM = {{')
for i in range(0, STEPS, 8):
line = ", ".join(f"{v:3}" for v in table[i:i+8])
print(" " + line + ",")
print("};")
ATTiny85ビルド方法
## -Wall : 詳細な警告を全て表示するようにする
## -Os : バイナリサイズが小さくなるよう最適化をする
## -mmcu=<Name> : プログラムを動かすマイコンを指定
# ビルド
avr-gcc -Os -Wall -mmcu=attiny85 AVR-Inverter.c -o test.elf
# elfからhexファイル作成
avr-objcopy -I elf32-avr -O ihex test.elf test.hex
# メモリ使用量を調べる
avr-size -C --mcu=attiny85 test.elf
@akira345
Copy link
Copy Markdown
Author

akira345 commented Jul 8, 2025

fusebit
ATTiny85ヒューズビット設定

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment