最近学んだ STM32 のシリアル通信。
シリアルポートは以前 51 を学んだときに使ったが、ほぼすっかり忘れてしまった(悲)
それではシリアル通信の復習を始めよう。
(一)USART とは何か#
シリアルポートは非常に広く使用されている通信インターフェースで、コストが低く、使いやすく、通信回路が簡単で、2 つのデバイス間の相互通信を実現できる。
マイコンのシリアルポートは、マイコン同士、マイコンとコンピュータ、マイコンとさまざまなモジュールが相互通信できるようにし、マイコンの応用範囲を大幅に拡大し、マイコンシステムのハードウェア能力を強化する。
その通信方式は非同期全二重で、非同期とは通信の両者間にクロック線が接続されておらず、事前にボーレート(伝送周波数)を設定する必要があることを指す;全二重とは通信の両者が信号を送受信でき、互いに干渉しないことを指す。
USART のシリアル通信には 2 本の線があり、1 本は TXD で信号を送信するために使用され、もう 1 本は RXD で信号を受信するために使用される。双方の TXD は相手の RXD と交差接続されている。(画像がなぜかアップロードできない、まあいいや)
USART が送信する完全な情報には、スタートビット、データビット、パリティビット、ストップビットが含まれ、その中でデータビットとパリティビットは合計で 8 または 9 ビットで、パリティビットは 1 ビットだけである。ストップビットの長さを変更することで送信周波数を変更できるが、一般的には 8 ビット無パリティまたは 9 ビットパリティを選択し、ストップビットの長さは 1 ビットで十分である。
(二)コード設定#
STM32 のライブラリ関数には専用の USART 関数があるため、設定プロセスは 51 よりもずっと簡単である。
コードは以下の通り:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate=9600; USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_WordLength=USART_WordLength_8b; USART_Init(USART1,&USART_InitStructure);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1,ENABLE);
私たちは、クロックをオンにしてピンを初期化した後、USART_Init で USART を初期化し(ボーレート 9600、8 ビット無パリティ)、次に USART_ITConfig で割り込みをオンにし、最後に NVIC を設定してシリアルポートを起動すればよい。
(三)信号の送信と受信#
信号を送信するのは非常に簡単で、USART_SendData 関数を使うだけである:
void Serial_SendByte(uint8_t Data)
{
USART_SendData(USART1,Data);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
}
この基礎の上に、文字列を送信する関数や数字を送信する関数をラップすることもできる。例えば、以下の文字列を送信する関数:
void Serial_SendString(uint8_t*Data)
{
int j = 0;
for(j=0;Data[j]!='\0';j++)
{
Serial_SendByte(Data[j]);
}
}
データを受信するには割り込みを使用する必要があり、コードは以下の通り:
void USART1_IRQHandler()
{
while(USART_GetITStatus(USART1,USART_IT_RXNE)==RESET);
SerialRXFlag=1;
SerialRXData=USART_ReceiveData(USART1);
}
(四)シリアルポートのデータパケットの送受信#
実際には、シリアルポートに特定の形式の内容を送受信させること、例えばデータパケットのヘッダーが 0xFF、パケットの末尾が 0xFE である。コードは大体以下の通り:
void Serial_Sendpacket()
{
Serial_SendByte(0xFF);
Serial_SendArray(SerialTXPacket,4);
Serial_SendByte(0xFE);
}
void USART1_IRQHandler()
{
static int pRXPacket = 0;
static uint8_t RxState = 0;
while(USART_GetITStatus(USART1,USART_IT_RXNE)==RESET);
uint8_t RXData = 0;
RXData = USART_ReceiveData(USART1);
switch (RxState)
{
case 0:
if (RXData == 0xFF)
{
RxState = 1;
pRXPacket = 0;
}
break;
case 1:
SerialRXPacket[pRXPacket] = RXData;
pRXPacket++;
if (pRXPacket >= 4)
{
RxState = 2;
}
break;
case 2:
if (RXData == 0xFE)
{
RxState = 0;
SerialRXFlag=1;
}
break;
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
USART の内容は大体これくらいで、特に複雑ではない。なぜなら、関数ライブラリが私たちが本来設定する必要がある一連のものをすでに処理してくれているからである。