C51マイクロコントローラのプログラムを多く調べた結果、現在インターネット上のC51マイクロコントローラのプログラムの質はまちまちであり、多くのプログラムのコードスタイルは非常に悪く、可読性も低いことが分かりました。初心者だけでなく、長年プログラミングをしているベテランプログラマーも同様であり、筆者も初心者時代にはプログラムが正常に動作するかどうかを重視し、プログラムの可読性、保守性、再利用性、拡張性を軽視していました。現在の職場では、コーディングスタイルと規則が非常に厳格に定められているため、C51マイクロコントローラのプログラムを記述する際のコーディング規則をまとめることにしました。本記事は猿学社上官一号開発ボード(コアはSTC89C52RC)を基に作成し、コーディングスタイルはK&Rスタイル(筆者は以前Linuxカーネルドライバ開発をしており、仕事ではこのスタイルを使用)で、変数と関数はアンダースコア命名法を使用します。
事前条件:
- C51の開発環境Keil uVision5がインストールされていること。インストールされていない場合は、ブログ「Keil MDKとKeil C51の共存方法」を参照してください。この記事ではSTM32などの主流の32ビットマイクロコントローラの開発環境を同時にインストールし、2つのソフトウェアの共存問題を解決しています。
- C51マイクロコントローラの書き込みツールをダウンロードしてください。ソフトウェアのダウンロード先:ツールソフトSTC-ISP
一、C51マイクロコントローラテンプレートの作成
テンプレートの利点は、新しいプロジェクトを作成する際に、チップ選定、必要なファイルの追加などの手順を省略できる点です。同じチップのプロジェクトであれば、テンプレートをコピーしてすぐにコーディング作業を開始できます。
テンプレートはGitHubとGiteeに同期済みです。ご指摘やご覧ください。
GitHubリンク
Giteeリンク
1. 新規プロジェクトの作成とチップ選定
Keil uVision5を実行し、最上段のメニューから「Project」をクリックし、ドロップダウンメニューが表示されたら、最初の「New μVision Project」を選択します。
続いて表示されるダイアログボックスで、プロジェクトを保存するフォルダを選択します。個人的な習慣として、すべてのコードを「Code」という名前のフォルダに保存し、その中でさらにコードの種類を具体的に分類します。C51のコードの場合は、専用のフォルダを新規作成して保存します。ここではデモンストレーションのために、DドライブにC51フォルダを直接新規作成しました。フォルダ内にさらにフォルダを作成し、「template」と名付け、つまりテンプレートの意味です。フォルダに入り、下のファイル名に再度「template」と入力し、「保存」をクリックします。
次にチップ選定のダイアログボックスが表示されます。私のKeilにはMDKバージョンが含まれているため、チップ選定時にはまず「Legacy Device Database」(旧デバイスデータベース)に切り替える必要があります。その後、以下の図のように操作してください。ここで、なぜ89C52を選択し、89C51を選択しなかったのか説明します。まず、両者は同じアーキテクチャであり、Intel 8051アーキテクチャです。上官一号が採用しているチップはSTC89C52RCであるため、89C52を選択しました。次に、C52はC51よりも多くの周辺機器を持っています。例えば、C51は4KBのROMをプログラムストレージスペースとして持ちますが、C52はより大きな8KBを持ち、C51は2つの16ビットタイマ/カウンタ(T0とT1)しか持っていませんが、C52は追加の16ビットタイマ/カウンタ(T2)を1つ多く持っています。もちろん、89C51を選択してもプログラムは正常にコンパイルされ、マイクロコントローラに書き込んで実行できる可能性がありますが、通常はチップと同じモデルを選択するのが最適です。
ただし、ここで誰もが気づいたかもしれませんが、現在のC51マイクロコントローラはほとんどがSTC(深圳宏晶科技)によって製造されています。なぜAT89C52でSTC89C52RCの代わりに使用できるのでしょうか?実際、どちらを選択しても問題ありません。89C52であれば、アーキテクチャが同じであればよいのです。
チップモデルを選択した後、続くダイアログボックスで「はい」を選択してください。さもないと、プログラムは正常にコンパイルできず、これはC51のスタートアップファイルです。
2. メインプログラムファイルの作成
左側のプロジェクトサイドバーで、「Target 1」→「Source Group 1」を順に展開し、「Source Group 1」を右クリックし、表示されるメニューから「Add New Item to Group 'Source Group 1'」を選択します。
続いて表示されるダイアログボックスで、以下の図のように操作し、「main.c」をメインプログラムファイルとして作成します。
作成が成功したら、以下のコードを基本テンプレートとして入力します。
/********************************************************************
* File:
* Description:
* Version:
* Date:
* Author:
* ---------- Revision History ----------
* <version> <date> <author> <desc>
*
********************************************************************/
#include "main.h"
/* ユーザーコードのインクルード */
/* ユーザーコードの定義 */
/* ユーザーコードのグローバル変数 */
/* ユーザーコードの関数プロトタイプ */
/* ------------------------------ 区切り線 ------------------------------ */
/**
* @brief すべての設定を初期化します。
*/
void initialize_system(void)
{
/* 初期化コードをここに記述します(一度だけ実行されます): */
}
/**
* @brief アプリケーションのエントリーポイント。
*/
void main_program(void)
{
/* プライベート変数 */
/* 初期化 */
initialize_system();
/* 無限ループ */
while (LOOP_FOREVER){
/* メインコードをここに記述します(繰り返し実行されます): */
}
}
このコードフレームワークの意味を簡単に説明します。Arduinoに慣れている方は、すぐにArduino IDEのデフォルトプログラムフレームワークをコピーしたことが分かるでしょう。initialize_system()は初期化用の関数で、この関数は一度だけ実行され、その後の繰り返し実行されるプログラムはmain_program()関数内のwhile(LOOP_FOREVER)に配置されます。他のコメントは主にCubeMXで生成されたKeilコードを参考にしています。具体的な説明は以下の通りです:
/* ユーザーコードのインクルード */:このコメントの下に他のヘッダーファイルを追加できます。/* ユーザーコードの定義 */:このコメントの下にプログラムが必要なマクロ定義を追加します。/* ユーザーコードのグローバル変数 */:このコメントの下にグローバル変数を追加します。/* ユーザーコードの関数プロトタイプ */:このコメントの下に関数プロトタイプを追加します。/* プライベート変数 */:main_program()関数内には/* プライベート変数 */もあります。C51はC90のエンコーディング標準を採用しているため、すべてのローカル変数は関数の最前端にしか書けません。そのため、このコメントを設け、main_program()関数のローカル変数をここに追加できます。
最前面の大きなコメントブロックはファイルの説明で、後で具体的に説明します。現在の効果は以下の図のようになります:
3. メインプログラムのヘッダーファイルの作成
皆さんも気づかれたかもしれませんが、メインファイルのmain.hヘッダーファイルは現在存在しません。また、whileループの条件はLOOP_FOREVERであり、これは現在存在しない変数またはマクロ定義です。したがって、次に対応するヘッダーファイルを作成します。
.cファイルの作成と同様に、ヘッダーファイルを作成するには「Header File(.h)」を選択するだけです。
そしてmain.hファイルに以下のコードを入力します:
/********************************************************************
* File: bit.h
* Description: 89C51/89C52メインヘッダーファイル。
* Version: 1.0
* Date: 2024-04-25
* Author: zhengxinyu13@gmail.com
* ---------- Revision History ----------
* <version> <date> <author> <desc>
*
********************************************************************/
#ifndef __MAIN_H__
#define __MAIN_H__
#include "STC89C5xRC-rdp.h"
#define HIGH_LEVEL 1
#define LOW_LEVEL 0
#define ENABLE 1
#define DISABLE 0
#define ACTIVATE 1
#define DEACTIVATE 0