前前回はGPIのAFを設定して前回は送信をやりました。
そしてやっと今回で受信です。
やりたいのは「z」という文字を受け取ったら「b」を送るというものです。
受信フラグ
実は難しいことは前回まででほとんどやってしまったので今回は楽です。
受信が完了したらSRレジスタのRXNEビットが1になるので、1になったらDRレジスタを読み出せば受信したデータが読めます。
#include "stm32f4xx.h" static void SetSysClock(void); void GPIO_init(void) { RCC-> AHB1ENR |= RCC_AHB1ENR_GPIOAEN; GPIOA-> MODER = 0x00000000; GPIOA-> PUPDR = 0x00000000; // no pullup down // PA2のAF7がUSART2_TX GPIOA-> AFR[0] = 0; GPIOA-> AFR[0] |= GPIO_AF7_USART2 << 8; GPIOA-> MODER |= 0b10 << 4; // PA2=AF // PA3のAF7がUSART2_RX GPIOA-> AFR[0] |= GPIO_AF7_USART2 << 12; GPIOA-> MODER |= 0b10 << 6; // PA3=AF } void UART_init( void) { RCC-> APB1ENR |= RCC_APB1ENR_USART2EN; USART2-> BRR = (22 << 4) + 13; USART2-> CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; } void UART_send(uint32_t character) { USART2->DR = character; while ((USART2->SR & USART_SR_TXE) == 0); } int main(void) { SetSysClock(); GPIO_init(); UART_init(); UART_send('a'); while(1) { if(USART2->SR & USART_SR_RXNE) { if (USART2->DR == 'z') { UART_send('b'); } } } } #define PLL_M 8 #define PLL_N 336 #define PLL_P 2 #define PLL_Q 7 #define PLLI2S_N 258 #define PLLI2S_R 3 static void SetSysClock(void) { __IO uint32_t StartUpCounter = 0, HSEStatus = 0; RCC->CR |= ((uint32_t)RCC_CR_HSEON); do { HSEStatus = RCC->CR & RCC_CR_HSERDY; StartUpCounter++; } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); if ((RCC->CR & RCC_CR_HSERDY) != RESET) { HSEStatus = (uint32_t)0x01; } else { HSEStatus = (uint32_t)0x00; } if (HSEStatus == (uint32_t)0x01) { RCC->APB1ENR |= RCC_APB1ENR_PWREN; PWR->CR |= PWR_CR_VOS; RCC->CFGR |= RCC_CFGR_HPRE_DIV1; RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; // APB2は84Mhz RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; // APB1は 42Mhz RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24); RCC->CR |= RCC_CR_PLLON; while((RCC->CR & RCC_CR_PLLRDY) == 0); FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS; RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); RCC->CFGR |= RCC_CFGR_SW_PLL; while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL); } else { GPIOD->ODR |= 1<<14; } RCC->CFGR &= ~RCC_CFGR_I2SSRC; RCC->PLLI2SCFGR = (PLLI2S_N << 6) | (PLLI2S_R << 28); RCC->CR |= ((uint32_t)RCC_CR_PLLI2SON); while((RCC->CR & RCC_CR_PLLI2SRDY) == 0); }
動かすと起動直後にa送ってきます。キーボードで小文字のzを送ってみましょう。
そうするとbという文字が受信できると思います。
前回のプログラムと違うところは、
まずCR1レジスタの受信有効化ビットREを1にしています。
USART2-> CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
そしてメインループのwhile(1)で受信を待ちます。
受信データが来て読み出せるようになったらSRレジスタのRXNEビットが1になりますから、1になるのを待っているわけです。
if(USART2->SR & USART_SR_RXNE) { if (USART2->DR == 'z') { UART_send('b'); } }
そして、1になったら読み出し、zかどうかをチェックします。
zだったらbを送信しています。
ちなみにRXNEビットはDRレジスタからデータを読みだした段階で自動的に0に戻ります。便利ですね。
DRとは
前回送信にもDRレジスタを。受け取ったデータの読み取りにもDRをつかいました。
実はDRレジスタというのは存在しなくて、これは書き込みと読み取りで別のレジスタを見るようになっている特殊なレジスタです。
リファレンスマニュアルにはこのようになっています。
本当は送信用のTDRと受信用のRDRがあるのですが、DRに書き込むとTDRに、DRを読むとRDRから読み込むことになります。
USARTの他の機能
STMのUSARTには他にもいろいろ機能があります。
まず、当然ながら受信したら割り込みといったことは出来ます。
それ以外にも複数マイコンとUSARTでつなぐLINという機能や赤外線通信に使えるIrDA。
などなど、いろいろな機能があります。
今回はシンプルな送受信をしましたが、リファレンスマニュアルを見ながらいろいろ使ってみましょう。
まとめ
- CR1のREビットを1にすると受信できるようになる
- 受信するとSRレジスタのRXNEが1になり、データはDRから読み出せる。
- 読みだすと自動的にRXNEは0に戻る
adコンバータの使い方も読みたいな