akira.kei が 2026年02月27日00時46分06秒 に編集
初版
タイトルの変更
8ピンPICのPIC12F1571/2を使う(その1):ノイズジェネレータ
タグの変更
PIC
PIC12F1571
PIC12F1572
記事種類の変更
セットアップや使用方法
ライセンスの変更
(MIT) The MIT License
本文の変更
[<前の記事](https://elchika.com/article/c1b27de3-b053-42db-b74d-eb178b940795/) : 次の記事> ## 別にPIC12F1571じゃなくても… [前の記事](https://elchika.com/article/c1b27de3-b053-42db-b74d-eb178b940795/)でシンセサイザーを作るみたいなことを書いたが、一般にシンセサイザーの音源はまずは[ノイズジェネレーター](https://musicfromouterspace.com/analogsynth_new/NOISETOASTER/NOISETOASTER.php)から作るべきなのだ。そしてデジタルノイズといえばM系列乱数で[LFSR](https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E5%B8%B0%E9%82%84%E3%82%B7%E3%83%95%E3%83%88%E3%83%AC%E3%82%B8%E3%82%B9%E3%82%BF)なんだ(用語がよくわかっていないので並べてみた)。いずれにしろピンにランダムタイミングでパルスを出すみたいなことで実質的なホワイトノイズを出してみる。 今回はPIC12F1571を選んでみたが、フルデジタルなので8pinで32MHz駆動であれば何でもいける。なお末尾が[1]ではなく[2]の方のPIC12F1572 はシリアルモジュールがあるので、MIDI信号を受けて16bitPWMでCVを出しつつゲート信号を出す、みたいなことに使えるはずだ。末尾が[1]のやつは通信機能がないのに知らずに沢山買ってしまい、今回みたいな単純作業というか力技に使ってやる予定だ。 ## 8ピンしかなくても大丈夫 電源を入れたらひたすらノイズを出すだけ、という潔い設計でやってみようか。  VDDとVSSは5V電源、RA0とRA1にはPickit4プログラマの通信線(ICSPDATとCLK)、RA3はリセットに接続するので、ノイズを出すのはRA2、RA4及びRA5の3本にする。 今回もMCC Classicを使って楽をしてみることにするが、フルデジタルでCPUしか使わないためFOSCを32MHzにして、RA0/1/3を入力に、残りを出力にするだけで設定は終了だ。 ## メインルーチンは Copilotに書かせたので中身がよくわからない。まず```lfsr32```には0ではない初期値を入れる(``` 0x12345678```)。そして第31、21、1及び0ビットをXORをとって末端に入れたらシフトする、というのを繰り返すと疑似乱数が得られるらしい。 ```c: #include "mcc_generated_files/mcc.h" static uint32_t lfsr32 = 0x12345678; void main(void) { SYSTEM_Initialize(); uint32_t bit; while (1) { bit = ((lfsr32 >> 31) ^ (lfsr32 >> 21) ^ (lfsr32 >> 1) ^ (lfsr32 >> 0)) & 1; lfsr32 = (lfsr32 << 1) | bit; LATA=(uint8_t)lfsr32; } } ``` ちょっと8bitPICで32ビット整数を馬鹿正直にシフトしなくてもいいだろ、とも思うがこれでやってみた。するとどうも10kHzまではほぼ平坦なんだが、16kHzくらいに落ち込みがある。もう少しなんとかならんかな。 ## uint8_tに分解 Copilotの提案はどうもWikipediaと似たような感じだが、8bitのPICなので8bit毎に分解する。ただし、32bitシフトもできるようにしておかないといけないので、ちょっとunionしてみた。 ```c: #include "mcc_generated_files/mcc.h" typedef union { uint32_t ll; struct { uint8_t b0; uint8_t b1; uint8_t b2; uint8_t b3; }; } LFSR_u; static LFSR_u lfsr32; void main(void) { SYSTEM_Initialize(); lfsr32.ll=0x12345678; LFSR_u lfsr; bool b0,b1,b2,b3; while (1) { b3=(lfsr32.b3 & 0b10000000)?1:0; b2=(lfsr32.b2 & 0b00100000)?1:0; b1=(lfsr32.b0 & 0b00000010)?1:0; b0=(lfsr32.b0 & 0b00000001)?1:0; lfsr32.ll= (lfsr32.ll << 1) | ((b3^b2^b1^b0) & 1); LATA=lfsr32.b0; } } ``` こうすると```lfsr32 >> 31 ```などどいう無駄シフトを考えなくていい。ノッチも16kHzから80kHzまで上がった(黄色い線の方を参照)。20kHzくらいまでフラットだと思っていい。  ## もしかしてアセンブラ こんな変数に代入してシフトしながら無限ループする、なんて単純作業はアセンブラでも書けるんじゃね?と考えてやってみた。ソースは恥ずかしいし内容をよく理解していないので貼らないが、なんとノッチが258kHzまで伸びている。最小パルスの幅がこれくらいの周波数の逆数くらいになるということで、ほぼループの速さでもある。 