方形波のフーリエ級数による合成プログラム。 http://www.vector.co.jp/authors/VA000874/のリンク先http://homepage3.nifty.com/silo/FONTV/でダウンロードした VGON16.LZH のうち GONHN16X.TLF をQSPIフラッシュROMの0x90000000番地以降に、GONZN16X.TLF を0x90010000番地以降に配置してから実行して日本語表示をさせることが可能。
Dependencies: BSP_DISCO_F746NG_patch_fixed BUTTON_GROUP LCD_DISCO_F746NG QSPI_DISCO_F746NG TS_DISCO_F746NG mbed
Diff: main.cpp
- Revision:
- 0:529a855826ec
- Child:
- 1:da55c6735fa0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Feb 01 11:23:42 2016 +0000 @@ -0,0 +1,405 @@ +//-------------------------------------------------------------- +// F746_Fourier_series_of_square_wave_01 +//-------------------------------------------------------------- + +#include "mbed.h" +#include <stdlib.h> +#include <string.h> +#include "LCD_DISCO_F746NG.h" +#include "TS_DISCO_F746NG.h" +#include "QSPI_DISCO_F746NG.h" +#include "button_group.hpp" +#include "sjis_utf_table.h" + +using namespace Mikami; + +LCD_DISCO_F746NG lcd; // Object for LCD display +TS_DISCO_F746NG ts; // Object for touch pannel +QSPI_DISCO_F746NG qspi; +DigitalIn user_button(USER_BUTTON); +DigitalOut led1(LED1); +DigitalOut led2(LED2); + +#define BUFFER_SIZE ((uint32_t)32) +#define NB 0x10011; // 全角フォントのコード・ブロック数 NBがあるオフセットアドレス 0x11 +#define countof(x) ( sizeof(x) / sizeof(x[0]) ) +#define LEN 60 + +const float PI = 3.141593f; +const int N_ = 480; +const double DT_ = ((2.2*PI)/(N_ - 1)); +const float DX_ = 0.3f; + +const uint32_t BACK_COLOR = 0xFF006A6C; // Teal green +const uint32_t INACTIVE_COLOR = BACK_COLOR & 0xD0FFFFFF; +const uint32_t TOUCHED_COLOR = 0xFF7F7FFF; +const uint32_t ORIGINAL_COLOR = 0xFF0068B7; +const uint32_t INACTIVE_TEXT_COLOR = LCD_COLOR_GRAY; +const uint32_t AXIS_COLOR = 0xFFCCFFFF; +const uint32_t LINE_COLOR = LCD_COLOR_CYAN; + +int order_ = 1; // フーリエ合成の次数 + +int x_size, y_size; //液晶画面の横・縦のドット数 +const float PI2 = PI*2; +const int FS_ = 48000; +const int MAX_ORDER_ = 199; // 使用する係数の最大の次数 +double bk1_[MAX_ORDER_]; // フーリエ係数 + +uint32_t hankaku_base_addr; // 半角フォントの先頭アドレス+0x90000000 +uint32_t zenkaku_base_addr; // 全角フォントの先頭アドレス+0x90010000 +uint32_t kanji_start_addr; +uint8_t WF; // 半角フォントのフォント幅 WF +char input_string[LEN]; // 表示文字列を入れる配列 +unsigned int output_utf8[LEN][3]; // 新check_utf8()の出力を受け取るための配列 + +struct point { + float x; + float y; +}; + +struct point ptn1_[N_]; + +void lcd_init(void); +void qspi_init(void); +void font_init(void); +void check_utf8(char *, unsigned int [256][3]); +void drawfont16(uint16_t, uint16_t, char, uint32_t); // draw 8x16 font +void draw_zenkaku(uint16_t, uint16_t, uint32_t, uint32_t); // draw 16x16 font +const char *findface(unsigned int); +void draw_string(uint16_t, uint16_t, char *, uint32_t); +char *itoa(int, char *, int); + +void Synthesize(void); // フーリエ合成関数 +void CreateCoefficients(void); // フーリエ係数生成関数 + +int main() +{ + int i, j; + + printf("Hello Discovery F746NG!\r\n"); + printf("SystemCoreClock: %d MHz\r\n\n", SystemCoreClock/(1000*1000)); + CreateCoefficients(); // フーリエ係数の生成 + qspi_init(); + lcd_init(); + font_init(); + draw_string(0, 0, "方形波のフーリエ級数による合成", LCD_COLOR_WHITE); + draw_string(0, 250, "フーリエ級数の次数 N =", LCD_COLOR_WHITE); + // Setting of button group + const string DOWN_UP[2] = {"DOWN", "UP"}; // downUP は フーリエ級数の時数を増減させるためのボタングループ + ButtonGroup downUp(lcd, ts, 350, 230, 60, 40, ORIGINAL_COLOR, BACK_COLOR, 2, DOWN_UP, 5, 0, 2); + downUp.Draw(0, INACTIVE_COLOR, INACTIVE_TEXT_COLOR); + downUp.Draw(1, TOUCHED_COLOR, INACTIVE_TEXT_COLOR); + + while (1) { + Synthesize(); // フーリエ係数で波形を合成 + for (i = 0; i < x_size-20; i++) + { + lcd.DrawPixel(i, ptn1_[i].y + 100, LCD_COLOR_WHITE); + } + downUp.Draw(0, TOUCHED_COLOR, INACTIVE_TEXT_COLOR); + downUp.Draw(1, TOUCHED_COLOR, INACTIVE_TEXT_COLOR); + while (!downUp.Touched(0, TOUCHED_COLOR) && !downUp.Touched(1, TOUCHED_COLOR)) {} // ボタンが押されるのを待つ + if (downUp.Touched(1, TOUCHED_COLOR)) { + printf("UP Touched\n"); + if (order_ < 199) { + order_++; + } + lcd.Clear(BACK_COLOR); + }else if (downUp.Touched(0, TOUCHED_COLOR)) { + printf("DOWN Touched\n"); + if (order_ > 1) { + order_--; + } + lcd.Clear(BACK_COLOR); + } + itoa(order_, input_string, 10); + draw_string(182, 250, input_string, LCD_COLOR_WHITE); + draw_string(0, 0, "方形波のフーリエ級数による合成", LCD_COLOR_WHITE); + draw_string(0, 250, "フーリエ級数の次数 N =", LCD_COLOR_WHITE); + } +} + + +void lcd_init(void) +{ + lcd.Clear(BACK_COLOR); + lcd.SetTextColor(LCD_COLOR_YELLOW); + lcd.SetFont(&Font20); + x_size = lcd.GetXSize(); + y_size = lcd.GetYSize(); +} + +void Synthesize(void) // bk1_[]を使用するハミング窓「なし」版 +{ + const float A0 = -50; + const double SHIFT = -0.1 * PI; + float xn[N_]; + int n, k; + +// printf("DT_ = %f\n", DT_); + for (n = 0; n < N_; n++) { + xn[n] = 0; + for (k = 1; k <= order_; k++) { + xn[n] = xn[n] + (float)(bk1_[k-1]*sin(k*(DT_*n + SHIFT))); + } +// printf("%f\n", n, xn[n]); + } + for (n = 0; n < N_; n++) { + ptn1_[n].x = DX_ * n; + ptn1_[n].y = A0 * xn[n]; +// printf("ptn1_[%d].x=%f : ptn1_[%d].y=%f\n", n, ptn1_[n].x, n, ptn1_[n].y); + } +} + +// フーリエ係数の生成 +void CreateCoefficients(void) +{ + int k; + const float FACTOR = 4.0/PI; // 4/π + + for (k=1; k<=MAX_ORDER_; k++) + { + if (k % 2 == 0) + { + bk1_[k-1] = 0; + }else{ + bk1_[k-1] = FACTOR/(double)k; + } + } +} + +// draw 8x16 font +void drawfont16(uint16_t Xpos, uint16_t Ypos, char c, uint32_t color) +{ + int i, j; + const short data[] = { + 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01, + }; + uint8_t ReadBuffer[BUFFER_SIZE]; + uint32_t addr; + addr = c * 0x10 + hankaku_base_addr; + qspi.Read(ReadBuffer, (uint32_t)addr, BUFFER_SIZE); + i = j = 0; + for (j = 0; j < 16; j++) { // 半角1文字分16Byteを読み出す + for (i = 0; i < 8; i++) { // メモリ1Byte分の8 + if (ReadBuffer[j] & data[i]) { + lcd.DrawPixel((Xpos + i), (Ypos + j), color); + } + } + } +} + + +// 文字列表示関数 +void draw_string(uint16_t Xpos, uint16_t Ypos, char *str, uint32_t color) +{ + int i = 0, j; + unsigned int utf8_code; + + check_utf8(str, output_utf8); + while (output_utf8[i][2] != 0) { + utf8_code = 0; + if (output_utf8[i][0] == 0) { // 1バイト文字の場合 + drawfont16(Xpos, Ypos, output_utf8[i][2], color); + Xpos += 8; + } else { // 2バイト文字(UTF-8)の場合 + utf8_code = output_utf8[i][0] << 16; + utf8_code += output_utf8[i][1] << 8; + utf8_code += output_utf8[i][2]; + draw_zenkaku(Xpos, Ypos, utf8_code, color); + Xpos += 16; + } + i++; + } + for (i = 0; i < LEN; i++) { + output_utf8[i][0] = 0; + } +} + +// findface() UTF-8コードを引数で受け取り、SJISに変換してフォントデータを検索し、先頭アドレスを返す +const char *findface(unsigned int utf8_code) +{ + const char *p = NULL; + unsigned int sjis_code; + int i; + uint32_t addr; + + for (i = 0; i < countof(utf8_sjis_table); i++) { + if (utf8_code == utf8_sjis_table[i].utf8) { + sjis_code = utf8_sjis_table[i].sjis; + } + } + // Shift-JISコードをもとにフォントテーブルデータを参照しフォントインデックス番号を得る + if (sjis_code < 0x879f) { + i = 0; + while (sjis_code != utf8_sjis_table[i].sjis) { + i++; + } + addr = zenkaku_base_addr + (utf8_sjis_table[i].line -1) * 0x10; + }else{ // SJISコード 0x889F 亜 以降の文字コードを持つ文字 + i = 523; + while (sjis_code != utf8_sjis_table[i].sjis) { + i++; + } + addr = kanji_start_addr + ((utf8_sjis_table[i].line - 2445) << 4); + } + p = (const char *)addr; + return p; +} + + +// draw 16x16 font +void draw_zenkaku(uint16_t Xpos, uint16_t Ypos, unsigned int utf8_code, uint32_t color) +{ + int i, j, k; + const short data[] = { + 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01, + }; + const char *p; + uint8_t ReadBuffer[BUFFER_SIZE]; + + p = findface(utf8_code); + if(p == NULL) return; + + if (qspi.Read(ReadBuffer, (uint32_t)p, BUFFER_SIZE)!= QSPI_OK) { + error("Read FAILED\n"); + } else { + ; + } + k = 0; + for (i = 0; i < 32; i++) { // 漢字1文字分32Byteを読み出す + if (k > 15) { // k=0,1,2,,,15 は漢字データの横1列16bit + k = 0; + } + for (j = 0; j < 8; j++) { // メモリ1Byte分の8 + if (ReadBuffer[i] & data[j]) { + lcd.DrawPixel((Xpos + k), (Ypos + i/2), color); + } + k++; + } + } +} + + +// 文字列を読み込み、1バイト半角英数文字と3バイトUTF-8文字の判別して +// 結果を2次元配列に返す関数 +// ※2バイトUTF-8文字は無視するので注意 +void check_utf8(char *sp, unsigned int utf8[256][3]) +{ + int i, j; // 文字数を数えながら、配列の添え字をインクリメントするための変数 + char c1 = 0, c2 = 0; + unsigned int i1, i2, i3; + + i = 0; + while (*sp != '\0') { + j = 0; + if ((*sp & 0xf0) == 0xe0) { // 上位4ビットが1110なら、3バイト文字の1バイト目 + c1 = *sp; + i1 = c1; + i1 *= 0x10000; + } else if ((*sp & 0xc0) == 0x80) { // 上位2ビットが10なら、他バイト文字の2バイト目以降 + if (c2 == 0) { + c2 = *sp; + i2 = c2; + i2 *= 0x100; + } else { + utf8[i][j] = c1; + j++; + utf8[i][j] = c2; + j++; + utf8[i][j] = *sp; + i3 = *sp; + i3 = i1 + i2 + i3; + c1 = c2 = 0; + i++; // 次の文字へ進む + } + } else if ((*sp & 0x80) == 0) { // 1バイト文字の場合 + utf8[i][2] = *sp; + i++; // 次の文字へ進む + } + sp++; + } + for (j = 0; j < 3; j++) { + utf8[i][j] = 0; // データの終りが必ず0になるように書き込む + } +} + +char *itoa( int val, char *a, int radix ) +{ + char *p = a; + unsigned int v = val;/* 作業用(変換対象の値) */ + int n = 1;/* 変換文字列の桁数記憶用 */ + while(v >= radix) { /* 桁数を求める */ + v /= radix; + n++; + } + p = a + n; /* 最下位の位置から設定する */ + v = val; + *p = '\0';/* 文字列終端の設定 */ + do { + --p; + *p = v % radix + '0';/* 1桁の数値を文字に変換 */ + if(*p > '9') {/* 変換した文字が10進で表現できない場合 */ + *p = v % radix - 10 + 'A'; /* アルファベットを使う */ + } + v /= radix; + } while ( p != a); + return a; +} + + +void qspi_init(void) +{ + QSPI_Info pQSPI_Info; + // Check initialization + if (qspi.Init() != QSPI_OK) { + led2 = 1; + error("Initialization FAILED\n"); + } else { + led1 = 1; + } + // Check memory informations + qspi.GetInfo(&pQSPI_Info); + if ((pQSPI_Info.FlashSize != N25Q128A_FLASH_SIZE) || + (pQSPI_Info.EraseSectorSize != N25Q128A_SUBSECTOR_SIZE) || + (pQSPI_Info.ProgPageSize != N25Q128A_PAGE_SIZE) || + (pQSPI_Info.EraseSectorsNumber != N25Q128A_SUBSECTOR_SIZE) || + (pQSPI_Info.ProgPagesNumber != N25Q128A_SECTOR_SIZE)) { + led2 = 1; + error("Get informations FAILED\n"); + } else { + ; + } + +} + + + +void font_init(void) +{ + uint8_t ReadBuffer[BUFFER_SIZE]; + uint32_t read_write_addr; + + // 半角フォント処理 + // フォントイメージ開始アドレスを求める + read_write_addr = 0x0d; // フォント幅(WF)を読み取る + if (qspi.Read(ReadBuffer, read_write_addr, 0x1) != QSPI_OK) { + led2 = 1; + error("Read FAILED\n"); + } else { + WF = ReadBuffer[0]; + hankaku_base_addr = 0x11; + } // 0x11はフォント先頭からフォントイメージまでのオフセット + + // 全角フォント処理 + // コード・ブロック数 NB を読み出し、フォントイメージ開始アドレスを求める + read_write_addr = NB; + if (qspi.Read(ReadBuffer, read_write_addr, 0x1) != QSPI_OK) { + led2 = 1; + error("Read FAILED\n"); + } else { + zenkaku_base_addr = 0x10000 + 0x12 + ReadBuffer[0] * 4; + } // 0x10000は全角フォントを0x90010000から配置してあるため 0x12はフォント先頭からNBまでのオフセット + kanji_start_addr = zenkaku_base_addr + 39104; // 39104はフォント先頭から漢字先頭"亜"までのオフセット +}