理論
一般的な情報
STM32L-Discoveryデバッグボードには、6つの14セグメント文字、4つのコロン文字(コロン)、4つのドット(DP)、4つのストリップ(バー)がある液晶インジケータ(LCD、英語LCD、液晶ディスプレイ)があります。 すべてのセグメントは、それぞれ24セグメントのOM0、COM1、COM2、COM3グループに結合されます。 各グループには、独自の「共通ワイヤ」があります。


マイクロコントローラSTM32L152RBT6はデバッグボードにインストールされます。 マイクロコントローラには、モノクロLCDインジケータを制御するLCDコントローラが組み込まれています。
LCDコントローラー:
- リフレッシュレート(フレームレート-LCDで情報が更新される頻度)を設定できます。
- 静的および多重制御モードをサポート
- ソフトウェアのコントラスト設定をサポート
- 制御電圧のいくつかのレベル(最大4つ)を使用できます
- ダブルバッファリングを使用します。これにより、表示される情報の整合性を損なうことなく、プログラムの実行時にいつでもLCD_RAMレジスタのデータを更新できます。
LCDコントローラメモリレジスタ
STM32L152RBマイクロコントローラには特別なLCD_RAMレジスタがあり、その情報はセグメントグループCOM0-COM3に対応しています。 各グループは、2つの32ビットレジスタに対応しています。 このような多数のレジスタにより、マイクロコントローラは、デバッグボードにインストールされているセグメントよりも多くのセグメントでLCDを制御できます。
LCDを176セグメントで制御するには、それぞれ44セグメントの4つのCOM0-COM3グループを使用し、320セグメントでLCDを制御するには、それぞれ40セグメントの8 COM0-COM7グループを使用します。


STM32L-Discoveryデバッグボードは、96個のセグメントを持つLCDを使用し、それぞれが24個のセグメントを持つ4つのグループCOM0-COM3に分割されています。

STM32L-Discoveryデバッグボード上のLCDは、各グループの2番目のLCD_RAMレジスタのビットS40、S41と最初のLCD_RAMレジスタのビットS0-S27が使用されるように接続されます。 使用されるレジスタの数を減らすために、ビットS40-S43からの情報は、リマッピング機能を使用して空きビットS28-S31に記録されます。
分周器ブロック
Frequency generatorブロックを使用すると、LCDで32 kHz〜1 MHzの範囲で異なるフレームレートを実現できます。 クロック信号のソースとして使用できます:
- 32 kHz外部低周波発振器(LSE。低速外部)
- 37 kHz内部低周波発振器(LSI。低速内部)
- 2.48および16の分周器と1 MHzの最大周波数を持つ外部RFジェネレーター。 (HSE。高速外部)
正確な同期を実現し、LCDセグメント全体のDC電圧バイアスを低減するには、クロックソースが安定している必要があります。 LCDCLKクロック信号はLCDコントローラーに送信されます。 クロック周波数は、LCD_FCRレジスタ(フレーム制御レジスタ)のPS [3:0]、DIV [3:0]ビットで設定される分割係数に従って分割されます。 分周器のブロックの出力での結果の周波数は、次の式で計算されます。
f ck_div = F LCDCLK /(2 PS *(16 + DIV))
フレームレートは次の式で計算されます。
f フレーム = f ck_div *デューティ
ここで、デューティはデューティサイクルであり、パルス周期と周期の比です。 1フレーム中、LCD_RAM [x]、LCD_RAM [x + 1]などのレジスタからの情報がLCDに順次表示されます。 デバッグボードにインストールされたLCDの場合、1フレームの場合、LCDコントローラーはセグメントCOM0-COM3の4つのグループから情報を出力する必要があります。したがって、1つのグループの制御パルス持続時間はフレーム持続時間の1/4です。 デューティ= 1/4。
LCD管理
LCDを制御するには、静的制御モードと多重制御モードの2つの方法があります。 静的表示では、インジケータ放電の各セグメントがマイクロコントローラの出力に接続されます。 LCDに関連して、STM32LDiscoveryデバッグボードには、マイクロコントローラーの6 * 14 = 84ピンが必要です(コロン、ドット、ストライプを除く)。 非常に多くのピンを使用するため、他の周辺機器への接続は不可能になります。 STM32L152RBマイクロコントローラには64ピンがあります。 多重制御モード(動的制御モード)では、インジケータビットの同じセグメントがグループに結合されます。 情報は、インジケータビットのセグメントが交互に発火するために表示され、周波数は人間の目では認識されません。
多重制御により、多数のセグメントを管理できます。 各要素を個別に制御する代わりに、行と列(COMおよびSEG)でアドレス指定できるため、制御回路が簡素化されます。 各セグメントは、独自の制御線を必要としません。 選択したセグメントを有効にするには、電位差COMとSEGを適用する必要があります。 インジケーターの最初の放電の例(「1:」がインジケーターに表示されます):

時刻t 0でのインジケーターの最初の数字

時刻t 1でのインジケーターの最初の数字

時刻t 2でのインジケーターの最初の桁

セグメントをLCD端子に接続するための一般的なスキーム

LCD端子をマイクロコントローラーのポートに接続するスキーム
SEGラインの場合、制御電圧が使用され、そのレベル数はバイアス係数によって決まります。 デバッグボード上のLCDは、デューティ= 1/4およびバイアス= 1/3のマルチプレックス制御モードを使用します。 デューティとバイアスの値は、LCD_CR(制御レジスタ)のビットDUTY [2:0]およびBIAS [1:0]で設定されます。
練習する
マイクロコントローラーポートの構成
LCDを制御するには、それに応じてマイクロコントローラーのポートを構成する必要があります。
- 出口で
- 代替機能AF 11(代替機能)を使用する
- 400 kHzポートで出力周波数を持っている
- プッシュプルモードを使用する
- プルアップ抵抗なし
ポートが代替機能モードの場合、ポートの出力データバッファは周辺からの信号によって制御されます。 CMSISライブラリのヘッダーファイルstm32lxx.hには、すべての周辺レジスタの説明とそのアクセス構造が含まれています。
LCDピンは、マイクロコントローラーのGPIOA(PA1-PA3、PA8-PA10、PA15)、GPIOB(PB3-PB5、PB8-PB15)、GPIOC(PC0-PC3、PC6-PC11)ポートに接続されます。 LCDを機能させるには、選択したポートにクロック信号を適用する必要があります。 マイクロコントローラのGPIOポートのクロッキングは、RCC(リセットおよびクロック制御)システム(クロッキングおよびリセットシステム)のAHBバスから行われます。 クロック信号は、RCC_AHBENR(AHBペリフェラルクロックイネーブルレジスタ)レジスタの対応するビットを設定することにより供給されます。

レジスタRCC_AHBENR(図は最初の15桁を示しています)
GPIOA、GPIOB、GPIOCポートの場合、レジスタの1〜0、1、2ビットを設定する必要があります。
次に、ビットマスクと16進コードを使用してレジスタに情報を書き込むコードを引用します。 ビットマスクを使用する方が便利ですが、16進コードを使用すると、レジスタを使用する本質を理解できます。
RCC->AHBENR |=(RCC_AHBENR_GPIOAEN|RCC_AHBENR_GPIOBEN|RCC_AHBENR_GPIOCEN); RCC->AHBENR = 0x7; /* 0x7=111 */
GPIOx_MODER(GPIOポートモードレジスタ)レジスタ(x = A..H)は、ポートの動作モードを示すために使用されます。 レジスタのすべてのビットは、MODERyグループ[1:0]にグループ化されます。yは対応するポートのピン番号です。 ポートは、代替機能モード、つまり ピンを担当するグループで、値を10に設定します。GPIOAポートの場合、ピン1-3.8-10.15を構成する必要があります。つまり、1を3,5,7,17,19,21,31ビットに設定する必要があります。

GPIOx_MODERレジスタ(GPIOポートモードレジスタ)
GPIOA->MODER |= (GPIO_MODER_MODER1_1 | GPIO_MODER_MODER2_1 | GPIO_MODER_MODER3_1 | GPIO_MODER_MODER8_1 | GPIO_MODER_MODER9_1 | GPIO_MODER_MODER10_1 | GPIO_MODER_MODER15_1); GPIOA->MODER = 0x802A00A8; /* 0x802A00A8=1000 0000 0010 1010 0000 0000 1010 1000 */
マイクロコントローラーポートはプッシュプルモードにする必要があります。 このためには、GPIOx_OTYPER(GPIOポート出力タイプレジスタ)レジスタのピンを担当するビットに1を設定する必要があります。

GPIOx_OTYPERレジスタ(GPIOポート出力タイプレジスタ)
GPIOA->OTYPER &= ~(GPIO_OTYPER_OT_1 | GPIO_OTYPER_OT_2 | GPIO_OTYPER_OT_3 | GPIO_OTYPER_OT_8 | GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10 | GPIO_OTYPER_OT_15); GPIOA->OTYPER &= ~0x0000870E; /* 0x870E=1000 0111 0000 1110 */
両方のオプションは、選択したピンに影響します。 (GPIOAポートの場合、ピン1-3.8-10.15が構成されます)。 ポートのすべてのピンをプッシュプルモードにする必要がある場合は、レジスタに値を書き込むことができます。
GPIOA->OTYPER = 0x0;
GPIOx_OSPEEDR(GPIOポート出力速度レジスタ)は、ポートに出力される情報の頻度を示すために使用されます。 すべてのレジスタビットは、OSPEEDRy [1:0]グループにグループ化されます。ここで、yは対応するポートのピン番号です。 この作品では、400 kHzの周波数、すなわち ピンを担当するグループで、値を00に設定します。

GPIOx_OSPEEDRレジスタ(GPIOポート出力速度レジスタ)
GPIOA->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR1 | GPIO_OSPEEDER_OSPEEDR2 | GPIO_OSPEEDER_OSPEEDR3 | GPIO_OSPEEDER_OSPEEDR8 | GPIO_OSPEEDER_OSPEEDR9 | GPIO_OSPEEDER_OSPEEDR10 | GPIO_OSPEEDER_OSPEEDR15); GPIOA->OSPEEDR &= ~0xC03F00FC; /*0xC03F00FC=1100 0000 0011 1111 0000 0000 1111 1100 */
すべてのピンの出力周波数を400 kHzポートに設定する必要がある場合、レジスタに値を書き込むことができます。
GPIOA->OSPEEDR = 0x0;
GPIOx_PUPDR(GPIOポートプルアップ/プルダウンレジスタ)は、選択されたピンのプルアップおよびプルダウンプルアップ抵抗を無効にするために使用されます。 レジスタのすべてのビットはPUPDRyグループ[1:0]にグループ化されます。yは対応するポートのピン番号です。 ピンを担当するグループのプルアップ抵抗を無効にするには、値00を設定します。

GPIOx_PUPDRレジスタ(GPIOポートプルアップ/プルダウンレジスタ)
GPIOA->PUPDR &= ~(GPIO_PUPDR_PUPDR1 | GPIO_PUPDR_PUPDR2 | GPIO_PUPDR_PUPDR3 | GPIO_PUPDR_PUPDR8 | GPIO_PUPDR_PUPDR9 | GPIO_PUPDR_PUPDR10 | GPIO_PUPDR_PUPDR15); GPIOA->PUPDR &= ~0xC03F00FC; /*0xC03F00FC=1100 0000 0011 1111 0000 0000 1111 1100 */
すべてのピンのプルアップ抵抗を無効にする必要がある場合は、レジスタに値を書き込むことができます。
GPIOA->PUPDR = 0x0;
マイクロコントローラーのポートに代替機能を使用するには、最低ピン(0から7)を担当する2つのレジスタGPIOx_AFRL(GPIO代替機能低レジスタ)と最高ピン(8から15)を担当するGPIOx_AFRH(GPIO代替機能高レジスタ)が使用されます。 レジスタのすべてのビットは、グループAFRLy [3:0]およびAFRHy [3:0]にグループ化されます。ここで、yは対応するポートのピン番号です。 ポートは代替機能AF11を使用するように構成する必要があります。そのためには、ピンを担当するグループで値1011を設定する必要があります。

GPIOx_AFRLレジスタ(GPIO代替機能低レジスタ)

GPIOx_AFRHレジスタ(GPIO代替機能高レジスタ)
これを行うには、レジスタに値を書き込みます。
GPIOA->AFR[0] = 0xBBB0; /* 0xBBB0 = 1011 1011 1011 0000*/ GPIOA->AFR[1] = 0xB0000BBB; /* 0xB0000BBB=1011 0000 0000 0000 0000 1011 1011 1011*/
AFR [0] = 0xBBB0-GPIOx_AFRLレジスタに値を書き込みます。
AFR [1] = 0xB0000BBB-GPIOx_AFRHレジスタに値を書き込みます。
対応するGPIOB、GPIOCポートピンの設定も同じ方法で行われます。
LCDコントローラのセットアップ
他の周辺機器と同様に、LCDコントローラーを使用する場合、それにクロック信号を適用する必要があります。 クロック信号も電源管理システムに提供されます。 コントローラと電源管理システムは、クロッキングにAPB1バスを使用します。 RCC_APB1ENRレジスタ(APB1周辺クロックイネーブルレジスタ)でクロッキングを有効にするには、9桁目と28桁目に1を設定する必要があります。

レジスタRCC_APB1ENR(APB1周辺クロックイネーブルレジスタ)
RCC->APB1ENR |= RCC_APB1ENR_PWREN|RCC_APB1ENR_LCDEN; RCC->APB1ENR |= 0x10000200; /* 0x10000200=1 0000 0000 0000 0000 0010 0000 0000 */
LCDコントローラの操作には、クロック信号のソースを示す必要があります。 ソースはレジスタRCC_CSRに示されています。 デフォルトでは、このレジスタへの書き込みは禁止されています。 電力制御レジスタPWR_CR(PWR電力制御レジスタ)では、RCC_CSRレジスタの書き込み保護が解除されます。 RCC_CSRレジスタは、RTCおよびLCDコントローラーのクロックソースを制御します
PWR_CRレジスタの8桁目に1を設定すると、RCC_CSRレジスタへの書き込みが有効になります。

PWR_CRレジスタ(PWR電力制御レジスタ)
PWR->CR |= PWR_CR_DBP; PWR->CR |= 0x100; /* 0x100 =1 0000 0000 */
LCDコントローラーのクロックソース(およびRTCクロックも)を変更するには、最初にRCC_CSR(制御/ステータスレジスタ)レジスタのRTCRSTビット(1を23番目のビットに設定)を設定して、クロックソースをリセットする必要があります。

レジスタRCC_CSR(制御/ステータスレジスタ)
RCC->CSR |= RCC_CSR_RTCRST;
または、演算子| | =を使用してレジスタに値を書き込むことにより、 価値
デフォルトのレジスタは0x0とは異なります。
RCC->CSR |= 0x800000; /* 0x800000 = 1000 0000 0000 0000 0000 0000 */
新しいクロックソースを選択するには、RTCRSTビットを削除する必要があります。
RCC->CSR &= ~RCC_CSR_RTCRST; RCC->CSR &= ~0x800000;
クロックソースとして外部バスジェネレーターが選択されています。 RCC_CSRレジスタでジェネレータを有効にするには、LSEONビットを設定する必要があります(1〜8ビットに設定)。
RCC->CSR |= RCC_CSR_LSEON; RCC->CSR |= 0x100; /* 0x100 = 1 0000 0000 */
発電機をオンにした後、安定させるのに時間がかかります。 ジェネレータの可用性は、RCC_CSRレジスタのLSERDYビットをハードウェアで設定することにより確認されます。
while(!(RCC->CSR&RCC_CSR_LSERDY));
外部LFジェネレーターは、RCC_CSRレジスタのRTCSEL [1:0]グループに値01を設定することにより、クロックソースとして選択されます。
RCC->CSR |= RCC_CSR_RTCSEL_LSE; RCC->CSR |= 0x10000; /* 0x10000 = 01 0000 0000 0000 0000 */
LCDコントローラで、目的のバイアスモードを設定する必要があります。 これを行うには、LCD_CR(LCD制御レジスタ)レジスタで、値10をBIASグループ[1:0]に設定する必要があります。 ビットを設定する前に、「ゴミ」からビットをクリアする必要があります。

レジスタLCD_CR(LCD制御レジスタ)
リセットビット:
LCD->CR &= ~LCD_CR_BIAS; LCD->CR &= ~0x60;
バイアスの選択=ビットマスクを使用した1/3:
LCD->CR |= LCD_CR_BIAS_1; LCD->CR |= 0x40;
デューティ= 1/4モードに設定します。 これを行うには、まずすべてのビットをリセットします。
LCD->CR &=~LCD_CR_DUTY; LCD->CR &= ~0x1C;
値011をLCD_CRレジスタのグループDUTY [1:0]に設定します
デューティモード= 1/4:
LCD->CR |= LCD_CR_DUTY_0|LCD_CR_DUTY_1; LCD->CR |= 0x;
結論のリダイレクト機能を有効にします。 これを行うには、LCD_CRレジスタの7桁目に1を設定します。
LCD->CR |= LCD_CR_MUX_SEG; <source lang=«C»>LCD->CR |= 0x80;
LCDCLKクロック信号の周波数の分周係数の値を設定します。 係数は、LCD_FCRレジスタ(LCDフレーム制御レジスタ)で設定されます。 最初に、すべてのビットもクリアしてから、必要なビットを設定します。

レジスタLCD_FCR(LCDフレーム制御レジスタ)
LCD->FCR &= ~LCD_FCR_PS; LCD->FCR &= ~LCD_FCR_DIV; LCD->FCR &= ~0x3C00000; LCD->FCR &= ~0x3C0000;
クロック周波数の分周係数の値は、ck_ps = LCDCLK / 16、ck_div = ck_ps / 17に設定されます。 これを行うには、1〜24および18桁を設定します。
LCD->FCR |= 0x1040000; /*0x1040000 = 1 0000 0100 0000 0000 0000 0000*/
目的のコントラストレベルを設定するには、値010をCCグループ[1:0]に設定する必要があります。また、以前の値からビットをクリアしたことがあります。
LCD->FCR &= ~LCD_FCR_CC; LCD->FCR |= LCD_FCR_CC_1; LCD->FCR &= ~0x1C00; LCD->FCR |= 0x800; /*0x800 = 1000 0000 0000*/
すべての値を設定した後、LCD_FCRレジスタの同期に時間がかかります。 レジスタの同期は、LCD_SRレジスタ(LCDステータスレジスタ)のFCRSFビットをハードウェアで設定することによりチェックされます。

レジスタLCD_SR(LCDステータスレジスタ)
while(!(LCD->SR&LCD_SR_FCRSR));
LCDの電圧源として、V lcdを形成する内部昇圧コンバータを選択します。 これを行うには、LCD_CRレジスタ(LCD制御レジスタ)の最初の桁を0に設定します。
LCD->CR &= ~LCD_CR_VSEL; LCD->CR &= ~0x2;
LCDコントローラの動作は、LCD_CRレジスタ(LCD制御レジスタ)の1〜0ビットを設定することにより有効になります。
LCD->CR |= LCD_CR_LCDEN; LCD->CR |= 0x1;
電圧源として内部ステップアップコンバータをインストールしたら、準備が整うまで待つ必要があります。 可用性は、ハードウェアがLCD_SRレジスタ(LCDステータスレジスタ)のRDYビットを設定することで確認されます。
while(!(LCD->SR&LCD_SR_RDY));
LCDコントローラの操作を許可した後、その準備ができるまで待つ必要があります。 可用性は、ハードウェアがLCD_SRレジスタ(LCDステータスレジスタ)のENSビットを設定することで確認されます。
while(!(LCD->SR&LCD_SR_ENS));
LCDイメージング
インジケーターのすべてのセグメントは、それぞれ24セグメント(SEG0-SEG23)のグループCOM0-COM3に結合されます。 セグメントに関する情報は、LCDコントローラメモリのLCD_RAMレジスタに保存されます。 PCBレイアウトは、セグメント番号がLCD_RAMレジスタの桁番号に対応しないようになっています。

LCDの最初の桁に1を表示するには、セグメント1B、1Cを点灯する必要があります。 セグメント1BはグループCOM0に属し、セグメント1CはグループCOM1に属します。 したがって、それらに関する情報は、それぞれレジスタRAM [0](LCD_RAM0)、RAM [2](LCD_RAM2)に記録する必要があります。 セグメント1Bの場合、LCDSEG22出力が原因であり、その情報はRAMレジスタ[1](LCD_RAM1)のSEG40カテゴリに格納されます。 再割り当て機能を使用すると、RAMレジスタ[0](LCD_RAM0)のSEG28ビットがLCDSEG22セグメントを担当します。 セグメント1Cの場合、LCD LCDSEG1の出力が責任を持ち、その情報はRAMレジスタ[2](LCD_RAM2)のSEG1カテゴリに格納されます。

LCD->RAM[0]= 0x10000000; /*0x10000000 = 1 0000 0000 0000 0000 0000 0000 0000 */ LCD->RAM[2] = 0x2; /*0x2= 10 */
メモリレジスタに値を書き込む前に、LCDへの以前のデータ転送が完了したかどうかを確認する必要があります。 これを行うには、LCD_SR(LCDステータスレジスタ)レジスタのUDR(表示要求の更新)ビットがチェックされます。 LCDコントローラーには2つの出力バッファーがあり、情報は最初のバッファーに入力され、2番目のバッファーからLCDに表示されます。 UDRビットは、最初のバッファから2番目のバッファへの送信中に設定され、LCD_RAMレジスタの書き込みを保護します。
while(LCD->SR & LCD_SR_UDR);
LCD_RAMレジスタに情報を書き込んだ後、LCD_SRレジスタ(LCDステータスレジスタ)のUDRビットを設定する必要があります(1〜2ビットを設定)。
LCD->SR |= LCD_SR_UDR; LCD->SR |= 0x4; /*0x4 = 100 */

準備完了プロジェクトコード
#include "stm32l1xx.h" void gpio(void); void controller(void); int main() { gpio(); controller(); while(LCD->SR & LCD_SR_UDR); LCD->RAM[0]= 0x3E300FFF; LCD->RAM[2] = 0x2EB00382; LCD->RAM[6] = 0x400; LCD->SR |= LCD_SR_UDR; while(1); } void gpio(void) { RCC->AHBENR |= 0x7; GPIOA->MODER |= 0x802A00A8; GPIOB->MODER |= 0xAAAA0A80; GPIOC->MODER |= 0xAAA0AA; GPIOA->OTYPER &= ~0x870E; GPIOB->OTYPER &= ~0xFF38; GPIOC->OTYPER &= ~0xFCF; GPIOA->PUPDR &= ~0xC03F00FC; GPIOB->PUPDR &= ~0xFFFF0FC0; GPIOC->PUPDR &= ~0xFFF0FF; GPIOA->OSPEEDR &= ~0xC03F00FC; GPIOB->OSPEEDR &= ~0xFFFF0FC0; GPIOC->OSPEEDR &= ~0xFFFFF0FF; GPIOA->AFR[0] |= 0xBBB0; GPIOA->AFR[1] |= 0xB0000BBB; GPIOB->AFR[0] |= 0xBBB000; GPIOB->AFR[1] |= 0xBBBBBBBB; GPIOC->AFR[0] |= 0xBB00BBBB; GPIOC->AFR[1] |= 0xBBBB; } void controller(void) { RCC->APB1ENR |= 0x10000200; PWR->CR |= 0x100; RCC->CSR |= 0x800000; RCC->CSR &= ~0x800000; RCC->CSR |= 0x100; while(!(RCC->CSR&RCC_CSR_LSERDY)); RCC->CSR |= 0x10000; LCD->CR &= ~0x60; LCD->CR |= 0x40; LCD->CR &= ~0x1C; LCD->CR |= 0xC; LCD->CR |= 0x80; LCD->FCR &= ~0x3C00000; LCD->FCR &= ~0x3C0000; LCD->FCR |= 0x1040000; LCD->FCR &= ~0x1C00; LCD->FCR |= 0x800; while(!(LCD->SR&LCD_SR_FCRSR)); LCD->CR &= ~0x2; LCD->CR |= 0x1; while(!(LCD->SR&LCD_SR_RDY)); while(!(LCD->SR&LCD_SR_ENS)); }
UPD: GariksユーザーはRAMレジスタの値を生成するための便利なプログラムを書きました
参照:
- http://chipspace.ru/ STM32L-DISCOVERY。 LCDを接続する
- http://easyelectronics.ru ARM。 研修コース
- http://radiokot.ru/動的表示
- STM32 L1シリーズのディスカバリーキット-STM32L152 MCU