Arduboyで固定小数点と回転と
固定小数点で使用するsin, cos関数を作成した。
#include <Arduboy2.h> Arduboy2 arduboy; #define SCREEN_CENTER_X 64 #define SCREEN_CENTER_Y 32 #define SCREEN_LEFT -64 #define SCREEN_RIGHT 63 #define SCREEN_TOP -32 #define SCREEN_BOTTOM 31 typedef struct WordPoint { uint16_t x; uint16_t y; }; typedef struct BytePoint { uint8_t xl; // 小数部 int8_t xh; // 整数部 uint8_t yl; // 小数部 int8_t yh; // 整数部 }; typedef union FixPoint { WordPoint w; BytePoint b; }; #define X w.x // xの整数・小数部をひっくるめた値にアクセスする #define Y w.y // yの整数・小数部をひっくるめた値にアクセスする #define XH b.xh // xの整数部にアクセスする #define XL b.xl // xの小数部にアクセスする #define YH b.yh // yの整数部にアクセスする #define YL b.yl // yの小数部にアクセスする void setup() { arduboy.begin(); arduboy.setFrameRate(60); arduboy.clear(); } void loop() { if (!arduboy.nextFrame()) return; arduboy.clear(); static FixPoint pos; static uint8_t angle; if (arduboy.pressed(LEFT_BUTTON)) { pos.X -= (1 << 8); if (pos.XH < SCREEN_LEFT) pos.XH = SCREEN_LEFT; } else if (arduboy.pressed(RIGHT_BUTTON)) { pos.X += (1 << 8); if (pos.XH > SCREEN_RIGHT) pos.XH = SCREEN_RIGHT; } if (arduboy.pressed(UP_BUTTON)) { pos.Y -= (1 << 8); if (pos.YH < SCREEN_TOP) pos.YH = SCREEN_TOP; } else if (arduboy.pressed(DOWN_BUTTON)) { pos.Y += (1 << 8); if (pos.YH > SCREEN_BOTTOM) pos.YH = SCREEN_BOTTOM; } arduboy.fillCircle(pos.XH + SCREEN_CENTER_X, pos.YH + SCREEN_CENTER_Y, 2, WHITE); angle++; FixPoint c; c.X = pos.X + GetCos(angle) * 30; c.Y = pos.Y + GetSin(angle) * 30; arduboy.fillCircle(c.XH + SCREEN_CENTER_X, c.YH + SCREEN_CENTER_Y, 5, WHITE); arduboy.print("X="); arduboy.print(pos.XH); arduboy.print("\n"); arduboy.print("Y="); arduboy.print(pos.YH); arduboy.print("\n"); arduboy.display(); } const uint8_t sinTbl[] PROGMEM = { 0x00, 0x06, 0x0c, 0x12, 0x19, 0x1f, 0x25, 0x2b, 0x31, 0x38, 0x3e, 0x44, 0x4a, 0x50, 0x56, 0x5c, 0x61, 0x67, 0x6d, 0x73, 0x78, 0x7e, 0x83, 0x88, 0x8e, 0x93, 0x98, 0x9d, 0xa2, 0xa7, 0xab, 0xb0, 0xb5, 0xb9, 0xbd, 0xc1, 0xc5, 0xc9, 0xcd, 0xd1, 0xd4, 0xd8, 0xdb, 0xde, 0xe1, 0xe4, 0xe7, 0xea, 0xec, 0xee, 0xf1, 0xf3, 0xf4, 0xf6, 0xf8, 0xf9, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, }; int16_t GetSin(uint8_t angle) { int16_t result = 256; // 1 << 8 uint8_t n = angle & 0x7f; if (n < 64) { result = pgm_read_byte(sinTbl + n); } else if (n > 64) { result = pgm_read_byte(sinTbl + 128 - n); } return (angle > 128) ? -result : result; } int16_t GetCos(uint8_t angle) { return GetSin(angle + 64); }
sinテーブルの作成ツール
固定小数点に合わせるため、1周を256度とみなし、その4分の1(64個)のテーブルを作成する。
sintbl.py
# -*- coding: utf-8 -*- import math for angle in range(64): v = math.sin(angle * math.pi / 128) * 256 print(format(int(v), '#04x') + ',', end='') if angle % 16 == 15: print('')