ココを参考にC言語でプログラムを作成。
単に点滅させてもおもしろくないので、一捻り。
PWMを使ってふわっと点滅させてみたかったけど、
データシートにPWMのレジスタの説明があまりなかったので
GPIOをソフトウェア的にPWM制御
test.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
// レジスタブロックの物理アドレス
#define PERI_BASE 0x20000000
#define GPIO_BASE (PERI_BASE + 0x200000)
#define BLOCK_SIZE 4096
// ピン機能(BCM2835)
#define GPIO_INPUT 0x0 // 入力
#define GPIO_OUTPUT 0x1 // 出力
#define GPIO_ALT0 0x4
#define GPIO_ALT1 0x5
#define GPIO_ALT2 0x6
#define GPIO_ALT3 0x7
#define GPIO_ALT4 0x3
#define GPIO_ALT5 0x2
/* pin番号とLEDのヒモ付 */
#define LED_PORT_NO_GREEN 17
// gpio[n]: GPIO 関連レジスタ (volatile=最適化によって消滅させない→必ず実メモリにアクセスさせる)
static volatile unsigned int *gpio;
// gpio_init: GPIO 初期化(最初に1度だけ呼び出すこと)
void gpio_init ()
{
int fd;
void *gpio_map;
// /dev/mem(物理メモリデバイス)を開く(sudo が必要)
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
printf("error: cannot open /dev/mem (gpio_setup)\n");
exit(-1);
}
// mmap で GPIO(物理メモリ)を gpio_map(仮想メモリ)に対応づける
gpio_map = mmap(NULL, BLOCK_SIZE,
PROT_READ | PROT_WRITE, MAP_SHARED,
fd, GPIO_BASE );
if ((int) gpio_map == -1) {
printf("error: cannot map /dev/mem on the memory (gpio_setup)\n");
exit(-1);
}
// mmap 後は不要な fd をクローズ
close(fd);
// gpio[index]: 整数 uint32 の配列としてレジスタへのアクセスを確立
gpio = (unsigned int *) gpio_map;
}
// gpio_configure: ピン機能を設定する(ピンを使用する前に必ず設定)
// pin : (P1) 2,3,4,7,8,9,10,11,14,15,17,18,22,23,24,25,27
// (P5) 28,29,30,31
// mode: GPIO_INPUT, _OUTPUT, _ALT0, _ALT1, _ALT2, _ALT3, _ALT4, _ALT5
void gpio_configure (int pin, int mode)
{
int index;
unsigned int mask;
// ピン番号チェック
if (pin < 0 || pin > 31) {
printf("error: pin number out of range (gpio_configure)\n");
exit(-1);
}
// レジスタ番号(index)と3ビットマスクを生成
index = pin / 10;
mask = ~(0x7 << ((pin % 10) * 3));
// GPFSEL0/1 の該当する FSEL (3bit) のみを書き換え
gpio[index] = (gpio[index] & mask) | ((mode & 0x7) << ((pin % 10) * 3));
}
// gpio_set/clear: ピンをセット (3.3V),クリア (0V)
void gpio_set (int pin)
{
// ピン番号チェック(スピードを追求するなら省略してもよい)
if (pin < 0 || pin > 31) {
printf("error: pin number out of range (gpio_set)\n");
exit(-1);
}
// ピンに1を出力(3.3V 出力)
gpio[7] = 0x1 << pin; // GPSET0
}
void gpio_clear (int pin)
{
// ピン番号チェック(スピードを追求するなら省略してもよい)
if (pin < 0 || pin > 31) {
printf("error: pin number out of range (gpio_clear)\n");
exit(-1);
}
// ピンに0を出力(0V 出力)
gpio[10] = 0x1 << pin; // GPCLR0
}
int main ()
{
unsigned long int OffTime;
unsigned long int OnTime;
unsigned long int BaseTime;
signed long int i;
gpio_init(); /* アドレス空間を周辺ペリフェラルのアドレスにマッピング */
gpio_configure(LED_PORT_NO_GREEN, GPIO_OUTPUT); /* ポート動作モードを設定 */
BaseTime = 100;
while (1) {
/*
段階的にDuty比を変える
usleep()はus単位のウエイトなので
1周期は 10000us = 10ms = 100Hz周期で制御
*/
/* 消灯→点灯 */
for( i = 0; i <= 100 ; i=i+1 ){
gpio_set(LED_PORT_NO_GREEN);
OnTime = i*BaseTime;
usleep(OnTime);
gpio_clear(LED_PORT_NO_GREEN);
OffTime = (100 - i)*BaseTime;
usleep(OffTime);
}
/* 点灯→ 消灯 */
for(i = 100; i >= 0 ; i=i-1 ){
gpio_set(LED_PORT_NO_GREEN);
OnTime = i*BaseTime;
usleep(OnTime);
gpio_clear(LED_PORT_NO_GREEN);
OffTime = (100 - i)*BaseTime;
usleep(OffTime);
}
}
return 0;
}
0 件のコメント:
コメントを投稿