(これ以下のプログラムはMPLAB(R) XC8 C Compile V1.00コンパイラ仕様にて記述しています) #include <xc.h> #include <stdlib.h> main() { int d ; d = rand() ; // この行を実行する度に乱数が発生する }ですがぁ.....
#include <stdlib.h> static long randx; static char randf; void srand(unsigned x) { randx = x; randf = 1; } rand(void) { if(!randf) srand(1); // ここが問題の行です return((int)((randx = randx*1103515245L + 12345) >> 16) & 077777); }ってなっています。
rand(void) { if(!randf) srand(ここにアナログ値をセット); return((int)((randx = randx*1103515245L + 12345) >> 16) & 077777); }こんな感じです、接続されていないアナログ端子の電圧は不定(ノイズ利用)なので丁度よさげですね。
if(!randf) srand(analogRead(0)) ; // アナログ0番ピンより読込むに書き換えて2回再実行させた結果が下の図です。
rand(int min,int max) { int ans ; if(!randf) srand(1); ans = (int)(((randx = randx*1103515245L + 12345) >> 16) & 077777) ; return min + ans % (max - min + 1) ; }って書き換えてやればOKです。
d = rand(1,10) ; // この行を実行する度に乱数が発生すると行えば1〜10までの範囲で乱数が発生するわけです。
[疑似乱数発生関数:random] *1) (以下をコピー&ペーストしてファイル名random.cで保存しましょう) ----random.c----------------------------------------------------- #include <xc.h> #include "random.h" static long randomx ; // 疑似乱数の初期値を設定する処理 void randomSeed(long val) { unsigned int temp; if (val == 0) { while(1) { GO_nDONE = 1 ; // PICにアナログ値読取り開始を指示 while(GO_nDONE) ; // PICが読取り完了するまで待つ temp = ( ADRESH << 8 ) | ADRESL ; // 10ビットの分解能力です if (temp > 0) break ; } randomx = temp ; } else randomx = val ; // 指定数値をそのまま初期値とする } // 疑似乱数を発生させる処理 long random(long min,long max) { long d ; d = ((randomx = randomx*1103515245L + 12345) >> 16) & 077777 ; return min + d % (max - min + 1) ; } -----------------------------------------------------------------
(以下をコピー&ペーストしてファイル名random.hで保存しましょう) ----random.h----------------------------------------------------- #ifndef _RANDOM_H_ #define _RANDOM_H_ void randomSeed(long val) ; long random(long min,long max) ; #endif -----------------------------------------------------------------下記サンプルプログラムはPIC16F1827での使用例です。
----------------------------------------------------------------- #include <xc.h> #include "random.h" #define _XTAL_FREQ 8000000 // delay用に必要(クロック8MHzを指定) // コンフィギュレーション1の設定 // CLKOUTピンをRA6ピンで使用する(CLKOUTEN_OFF):内部クロックを使用する(FOSC_INTOSC) // 外部クロック監視しない(FCMEN_OFF):外部・内部クロックの切替えでの起動はなし(IESO_OFF) // 電源電圧降下常時監視機能ON(BOREN_ON):電源ONから64ms後にプログラムを開始する(PWRTEN_ON) // ウオッチドッグタイマー無し(WDTE_OFF): // 外部リセット信号は使用せずにデジタル入力(RA5)ピンとする(MCLRE_OFF) // プログラムメモリーを保護しない(CP_OFF):データメモリーを保護しない(CPD_OFF) __CONFIG(CLKOUTEN_OFF & FOSC_INTOSC & FCMEN_OFF & IESO_OFF & BOREN_ON & PWRTE_ON & WDTE_OFF & MCLRE_OFF & CP_OFF & CPD_OFF) ; // コンフィギュレーション2の設定 // 動作クロックを32MHzでは動作させない(PLLEN_OFF) // スタックがオーバフローやアンダーフローしたらリセットをする(STVREN_ON) // 低電圧プログラミング機能使用しない(LVP_OFF) // Flashメモリーを保護しない(WRT_OFF):電源電圧降下常時監視電圧(2.5V)設定(BORV_HI) __CONFIG(PLLEN_OFF & STVREN_ON & WRT_OFF & BORV_HI & LVP_OFF) ; // メインの処理 void main() { long ans ; OSCCON = 0b01110010 ; // 内部クロックは8MHzとする ANSELA = 0b00000000 ; // AN0-AN4は使用しない全てデジタルI/Oとする ANSELB = 0b00000000 ; // AN5-AN11は使用しない全てデジタルI/Oとする TRISA = 0b00000000 ; // ピン(RA)は全て出力に割当てる(RA5は入力のみとなる) TRISB = 0b00000000 ; // ピン(RB)は全て出力に割当てる PORTA = 0b00000000 ; // RA出力ピンの初期化(全てLOWにする) PORTB = 0b00000000 ; // RB出力ピンの初期化(全てLOWにする) // A/Dの設定(疑似乱数の初期値として利用する) ADCON1 = 0b10010000 ; // 読取値は右寄せ、A/D変換クロックはFOSC/8、VDDをリファレンスに ADCON0 = 0b00000101 ; // アナログ変換情報設定(AN1から読込む) __delay_us(5) ; // アナログ変換情報が設定されるまでとりあえず待つ // PWM(CCP3)の設定(LEDの点灯制御に利用する) CCPTMRS = 0b00010000 ; // CCP3機能はTimer4を使用する CCP3CON = 0b00001100 ; // PWM機能(モジュール)を使用する T4CON = 0b00000010 ; // TMR4プリスケーラ値を16倍に設定 CCPR3L = 0 ; // デューティ値は0で初期化 CCPR3H = 0 ; TMR4 = 0 ; // タイマー4カウンターを初期化 PR4 = 124 ; // PWMの周期を設定(1000Hzで設定) TMR4ON = 1 ; // TMR4(PWM)スタート randomSeed(0) ; // 乱数の初期値はアナログAN1を読みだして設定する // 0以外の数値ならその数値を初期値として設定する while(1) { ans = random(1,255) ;// 1〜255の範囲内で乱数を発生させる CCPR3L = (char)ans ; // 乱数値でPWMのデュティ比を可変させる __delay_ms(500) ; // 0.5秒後に繰り返し } } -----------------------------------------------------------------乱数の初期値をアナログから読み込む場合は、レジスタANSELx/TRISx/ADCON0で
randomSeed関数の変更(*1) 2016/04/14
【きむ茶工房ガレージハウス】
Copyright (C) 2006-2016 Shigehiro Kimura All Rights Reserved.