方形波のフーリエ級数による合成プログラム。 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

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はフォント先頭から漢字先頭"亜"までのオフセット  
+}