Skip to content

Instantly share code, notes, and snippets.

@akira345
Last active July 8, 2025 06:46
Show Gist options
  • Save akira345/244e0005b12bad0b8fcba5b9afec6905 to your computer and use it in GitHub Desktop.
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
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