マイクロコンピュータではシリアル通信が多く使われてきた。少々古めかしい感じはするが,RS232Cにて通信を行うこととする。
テストでは,WindowsPCのTeraTermProとの交信を行う。
ここではSTM32F303VCT6 Usart1 を用い,8bit 1stop noparity baud115200 のプロトコルで交信する。
TX(send) : PA9
RX(receive) : PA10
に割り当てられる。
また,リングバッファ+Usart割り込みを使った,取りこぼしを避けるUsart通信の関数群も作成した。
マニュアルDM00058181.pdfのTable 12.Alternate functions for port Aによれば,USART1_TX,USART1_RXは,AF7の設定でPA9,PA10になっていることがわかる。
あるいはTable 13.Alternate functions for port Bによれば,USART1_TX,USART1_RXは,AF7の設定でPB6,PB7の設定も可能である。
(1)PA9,PA10ピンの設定
1)GPIOのPort Aを使うため,これにクロックを供給する。RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
2)PA9,PA10をAlternate function 7に設定する。
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_7);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_7);
3)この2つのピンをAlternate function Modeにする。
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
(2)Usartの設定
1)Usartを使うため,これにクロックを供給する。RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
2)通信速度baudrateの設定
USART_InitStructure.USART_BaudRate = 115200;
3)ビット長の設定
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
4)ストップビット長の設定
USART_InitStructure.USART_StopBits = USART_StopBits_1;
5)パリティビットなしに設定
USART_InitStructure.USART_Parity = USART_Parity_No;
6)ハードウェアフローコントロールなしに設定
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
7)RXとTXを使うモード
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
3.1 Usart関係の関数
(1)初期化関数
void Usart1_Init(void)
(2)1文字入力関数,文字コードを返す。1文字取得するまで待つことになる
int16_t Usart1_getchar(void)
(3)入力チェックと1文字入力関数,文字コードを返す。文字が入力されていなかったら-1を返す。
この関数は1文字を待つことはしない。
int16_t Usart1_checkgetchar(void)
(4)文字列を入力する。\rが入るまでを文字列とし,\nは無視する。
void Usart1_getstring(char *buff, int32_t max)
(5)1文字出力する関数
void Usart1_putchar(int16_t ch)
(6)文字列を出力する関数。\0までを送信
void Usart1_putstring(char *pch)
ここから下はオプション
(1)printf と同じ動作をする。
void Usart1_printf(char *format,...)
(2)プロンプト文字列を表示して整数を入力する。 x=Usart1_getInt("key in your number");の様に用いる。
int32_t Usart1_getInt(char *prompt)
3.2 Usart関数ファイル
usart_funcs.h
#ifndef __USART_FUNCS_H__
#define __USART_FUNCS_H__
#include <stm32f30x_conf.h>
void Usart1_Init(void);
int16_t Usart1_getchar(void);
int16_t Usart1_checkgetchar(void);
void Usart1_getstring(char *buff, int32_t max);
void Usart1_putchar(int16_t ch);
void Usart1_putstring(char *pch);
//ここから下はオプション,消去してもよい
void Usart1_printf(char *format,...);
int32_t Usart1_getInt(char *prompt);
#endif /*__USART_FUNCS_H__*/
usart_funcs.c
#include<stdarg.h>
#include "usart_funcs.h"
void Usart1_Init(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_7);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_7);
// Configure USART1 pins: RX(PA10) and TX(PA9)
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitTypeDef USART_InitStructure;
USART_DeInit(USART1);
USART_StructInit(&USART_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
//USART_WordLength_9b is available
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1,ENABLE);
}
int16_t Usart1_getchar(void)
{
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return USART_ReceiveData(USART1);
}
int16_t Usart1_checkgetchar(void)
{
if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET) return -1;
return USART_ReceiveData(USART1);
}
/*文字列入力'\r'が終端だが,'\r','\n'は取得されない*/
/*^Hでバックスペイス*/
void Usart1_getstring(char *buff, int32_t max)
{
int32_t i, ch;
for (i=0; i<max-1; i++) {
ch=Usart1_getchar(); /*1文字取得*/
*buff=(char)ch; /*1文字取得*/
if (*buff=='\r'||ch<0) {
break;
}
if (*buff==0x8) {
buff-=2;
i-=2;
}
if (*buff!='\n') buff++;
else i--;
}
*buff=0;
}
void Usart1_putchar(int16_t ch)
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, ch);
}
void Usart1_putstring(char *pch)
{
while(*pch) Usart1_putchar(*pch++);
}
/////////////////////////////////ここから下はオプション////////////////////
/////////////////////////////////消去してもよい////////////////////////
static int32_t atoi(char *buff)
{
int32_t x=0,y,m=0,n=0,v=0,i=0;
y=buff[i];
while(y!=0){
if(y=='-') m=1;
if('a'<=y&&y<='z') y=y-'a'+'A';
if(y=='0') n=1;
if(v==1){
if('0'<=y&&y<='9'){
y=y-'0';
}
else if('A'<=y&&y<='F'){
y=y-'A'+10;
}
x=16*x+y;
}
if(n==1&&y=='X'){
v=1;
}
if(v==0&&'0'<=y&&y<='9'){
y=y-'0';
x=10*x+y;
}
y=buff[++i];
}
if(m==1) x=-x;
return x;
}
int32_t Usart1_getInt(char *prompt)
{
char buff[32];
Usart1_putstring(prompt);
Usart1_getstring(buff,32);
return atoi(buff);
}
static const char hexstring[]="0123456789abcdef0123456789ABCDEF";
#define MAXDIGIT 128
static void Device_printf(int device, char *format, va_list arg_ptr)
{
void (*device_putchar)(int16_t ch);
void (*device_puts)(char *ptr);
char buf[MAXDIGIT];
unsigned char flag=0; /*%d:bit2 l:bit1 %:bit0 */
unsigned char digit=0; /* 桁数 */
unsigned char minus=0;
char fill=' ',format1=' ';
unsigned char radix=10; /*N進基数*/
char sign=' ';
char *ptr=buf; /*出力文字ポインタ*/
unsigned char cntr=0; /*出力文字数カウンタ*/
unsigned char shift=0; /*16進シフト 0 or 6*/
unsigned char i;
unsigned long int value=0;
if (device==1) {
device_putchar=Usart1_putchar;
device_puts=Usart1_putstring;
} else {
return;
}
/*va_start(arg_ptr,format);*/
while (*format) {
format1=*format;
if (flag==0) {
if (format1=='%') {
flag=1;
digit=0;
fill=' ';
minus=0;
radix=0;
ptr=&buf[MAXDIGIT-1];
*ptr--='\0';
cntr=0;
shift=0;
sign='+';
} else {
device_putchar(format1);
}
} else {
if (format1=='l') {
flag|=2;
} else if ('0'<=(format1)&&(format1)<='9') {
if (digit==0 && format1=='0') {
fill='0';
} else {
digit=digit*10+((format1)-'0');
if (MAXDIGIT-2<digit) digit=MAXDIGIT-2;
}
} else if (format1=='-') {
minus=1;
} else if (format1=='d') {
flag|=4;
radix=10;
} else if (format1=='u') {
radix=10;
} else if (format1=='x') {
radix=16;
} else if (format1=='X') {
radix=16;shift=16;
} else if (format1=='o') {
radix=8;
} else if (format1=='b') {
radix=2;
} else if (format1=='p') {
radix=16;shift=16;digit=8;fill='0';flag|=2;
} else if (format1=='c') {
device_putchar((unsigned char)(va_arg(arg_ptr,int)));
flag=0;
} else if (format1=='s') {
if (digit) {
cntr=0;ptr=va_arg(arg_ptr,char *);
while (ptr[cntr]) cntr++; /*cntrは文字数*/
if (!minus) for (i=cntr;i<digit;i++) device_putchar(' ');
device_puts(ptr);
if (minus) for (i=cntr;i<digit;i++) device_putchar(' ');
} else {
device_puts(va_arg(arg_ptr,char *));
}
flag=0;
} else {
device_putchar(format1);
flag=0;
}
if (radix) {
switch (flag&6) {
case 0: /* unsig int */
value=(unsigned int)va_arg(arg_ptr,int);
break;
case 2: /* unsig long int */
value=va_arg(arg_ptr,long int);
break;
case 4: /* sig int */
value=(long int)va_arg(arg_ptr,int);
if ((long int)value<0) {
value=-(long int)value;
sign='-';
}
break;
case 6: /* sig long int */
value=va_arg(arg_ptr,long int);
if ((long int)value<0) {
value=-(long int)value;
sign='-';
}
break;
default:
break;
}
while (value) {
*ptr--=hexstring[value%radix+shift];
cntr++;
value/=radix;
}
if (cntr==0) {
*ptr--='0';
cntr++;
}
if (fill==' ') {
if (sign=='-') {
*ptr--='-';
cntr++;
}
if (!minus) for (i=cntr;i<digit;i++) device_putchar(' ');
device_puts(++ptr);
if (minus) for (i=cntr;i<digit;i++) device_putchar(' ');
} else {
for (;cntr<digit-1;cntr++) *ptr--='0';
if (sign!='-'&&cntr<digit) *ptr--='0';
else if (sign=='-') *ptr--='-';
device_puts(++ptr);
}
flag=0;
}
}
format++;
}
/*va_end(arg_ptr);*/
}
void Usart1_printf(char *format,...)
{
va_list arg;
va_start(arg, format);
Device_printf(1, format, arg);
va_end(arg);
}
3.3 チェック用main1
TeraTermProから受け取った文字をおうむ返しするチェック #include <stm32f30x.h>
#include <stdint.h>
#include "stm32f30x_conf.h"
#include "stm32f3_discovery.h"
#include <stdio.h>
#include "usart_funcs.h"
int main(void)
{
int32_t ch;
Usart1_Init();
while (1){
ch=Usart1_getchar();
Usart1_putchar(ch);
}
}
3.4 チェック用main2
TeraTermProと交信するチェック #include <stm32f30x.h>
#include <stdint.h>
#include "stm32f30x_conf.h"
#include "stm32f3_discovery.h"
#include <stdio.h>
#include "usart_funcs.h"
int main(void)
{
int32_t x;
Usart1_Init();
Usart1_printf("\n");
while (1){
x=Usart1_getInt("input decimal number ---->");
Usart1_printf("x=%d %x %b\n",x,x,x);
x=Usart1_getInt("input hexdecimal number ---->");
Usart1_printf("x=%d %x %b\n",x,x,x);
}
}
実行結果(TeraTermPro側の表示)
input decimal number ---->10000
x=10000 2710 10011100010000
input hexdecimal number ---->0xf4240
x=1000000 f4240 11110100001001000000
input decimal number ---->32768
x=32768 8000 1000000000000000
input hexdecimal number ---->0x10000
x=65536 10000 10000000000000000
input decimal number ---->65536
Sx=65536 10000 10000000000000000
input hexdecimal number ---->-0x10000
x=-65536 ffff0000 11111111111111110000000000000000
input decimal number ---->
x=0 0 0
input hexdecimal number ---->
CPUが他の作業をしている時に,大量のUsart入力があった場合に,取りこぼしてしまう可能性がある。
取りこぼしを避けるために,リングバッファとUsart受信割り込みが使われる。
また,送信時でも,リングバッファとUsart送信可能割り込みを用いると,CPUは複数データ送信時に送信終了まで別の作業に移れないという問題が解決される。
使用している関数の使用する側から見ると,3のプログラムと全く同じである。
そのため,チェック用の関数mainは3のプログラムのものがそのまま使える。
usart_funcs.h #ifndef __USART_FUNCS_H__
#define __USART_FUNCS_H__
#include "stm32f30x_conf.h"
void Usart1_Init(void);
int16_t Usart1_getchar(void);
int16_t Usart1_checkgetchar(void);
void Usart1_getstring(char *buff, int32_t max);
void Usart1_putchar(int16_t ch);
void Usart1_putstring(char *pch);
//ここから下はオプション,消去してもよい
void Usart1_printf(char *format,...);
int32_t Usart1_getInt(char *prompt);
#endif /*__USART_FUNCS_H__*/
usart_funcs.c #include<stdarg.h>
#include "usart_funcs.h"
//リングバッファの構成
#define BUFFSIZE 64
#define SIZEMASK BUFFSIZE-1
static int16_t SendingBuff[BUFFSIZE];
static volatile uint16_t ptrPutSB=0; //送信バッファ書き込みポインタ
static volatile uint16_t ptrGetSB=0; //送信バッファ読み出しポインタ
static int16_t ReceivedBuff[BUFFSIZE];
static volatile uint16_t ptrPutRB=0; //受信バッファ書き込みポインタ
static volatile uint16_t ptrGetRB=0; //受信バッファ読み出しポインタ
void Usart1_Init(void)
{
//RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable USART1 IRQ */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//NVIC_EnableIRQ(USART1_IRQn); // Enable IRQ for USART#x in NVIC
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_7);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_7);
// Configure USART1 pins: RX(PA10) and TX(PA9)
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitTypeDef USART_InitStructure;
USART_DeInit(USART1);
USART_StructInit(&USART_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
//USART_WordLength_9b is available
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1,ENABLE);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // enable IRQ on RX of USART1
//USART_ITConfig(USART1, USART_IT_TXE, ENABLE); // enable IRQ on TX of USART1
}
int16_t Usart1_getchar(void)
{
int16_t ret;
while (ptrPutRB==ptrGetRB);
ret=ReceivedBuff[ptrGetRB++];
ptrGetRB&=SIZEMASK;
return ret;
}
int16_t Usart1_getcheckchar(void)
{
int16_t ret;
if (ptrPutRB==ptrGetRB) return -1;
ret=ReceivedBuff[ptrGetRB++];
ptrGetRB&=SIZEMASK;
return ret;
}
/*文字列入力'\r'が終端だが,'\r','\n'は取得されない*/
/*^Hでバックスペイス*/
void Usart1_getstring(char *buff, int32_t max)
{
int32_t i, ch;
for (i=0; i<max-1; i++) {
ch=Usart1_getchar(); /*1文字取得*/
*buff=(char)ch; /*1文字取得*/
if (*buff=='\r'||ch<0) {
break;
}
if (*buff==0x8) {
buff-=2;
i-=2;
}
if (*buff!='\n') buff++;
else i--;
}
*buff=0;
}
void Usart1_putchar(int16_t ch)
{
while ((ptrPutSB+1==ptrGetSB)||(ptrPutSB==ptrGetSB+SIZEMASK));
SendingBuff[ptrPutSB++]=ch;
ptrPutSB&=SIZEMASK;
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
}
void Usart1_putstring(char *pch)
{
while(*pch) Usart1_putchar(*pch++);
}
void USART1_IRQHandler(void) {
// RX IRQ part
if (USART1->ISR & USART_ISR_RXNE) { // if RXNE flag in ISR is on then
ReceivedBuff[ptrPutRB++]=USART_ReceiveData(USART1); // save received character & clear flag;
ptrPutRB&=SIZEMASK;
}
// TX IRQ part
if (USART1->ISR & USART_ISR_TXE) { // If TXE flag in ISR is on then
if (ptrPutSB!=ptrGetSB) {
USART_SendData(USART1, SendingBuff[ptrGetSB++]);
ptrGetSB&=SIZEMASK;
} else {
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
}
}
/////////////////////////////////ここから下はオプション////////////////////
/////////////////////////////////消去してもよい////////////////////////
static int32_t atoi(char *buff)
{
int32_t x=0,y,m=0,n=0,v=0,i=0;
y=buff[i];
while(y!=0){
if(y=='-') m=1;
if('a'<=y&&y<='z') y=y-'a'+'A';
if(y=='0') n=1;
if(v==1){
if('0'<=y&&y<='9'){
y=y-'0';
}
else if('A'<=y&&y<='F'){
y=y-'A'+10;
}
x=16*x+y;
}
if(n==1&&y=='X'){
v=1;
}
if(v==0&&'0'<=y&&y<='9'){
y=y-'0';
x=10*x+y;
}
y=buff[++i];
}
if(m==1) x=-x;
return x;
}
int32_t Usart1_getInt(char *prompt)
{
char buff[32];
Usart1_putstring(prompt);
Usart1_getstring(buff,32);
return atoi(buff);
}
static const char hexstring[]="0123456789abcdef0123456789ABCDEF";
#define MAXDIGIT 128
static void Device_printf(int device, char *format, va_list arg_ptr)
{
void (*device_putchar)(int16_t ch);
void (*device_puts)(char *ptr);
char buf[MAXDIGIT];
unsigned char flag=0; /*%d:bit2 l:bit1 %:bit0 */
unsigned char digit=0; /* 桁数 */
unsigned char minus=0;
char fill=' ',format1=' ';
unsigned char radix=10; /*N進基数*/
char sign=' ';
char *ptr=buf; /*出力文字ポインタ*/
unsigned char cntr=0; /*出力文字数カウンタ*/
unsigned char shift=0; /*16進シフト 0 or 6*/
unsigned char i;
unsigned long int value=0;
if (device==1) {
device_putchar=Usart1_putchar;
device_puts=Usart1_putstring;
} else {
return;
}
/*va_start(arg_ptr,format);*/
while (*format) {
format1=*format;
if (flag==0) {
if (format1=='%') {
flag=1;
digit=0;
fill=' ';
minus=0;
radix=0;
ptr=&buf[MAXDIGIT-1];
*ptr--='\0';
cntr=0;
shift=0;
sign='+';
} else {
device_putchar(format1);
}
} else {
if (format1=='l') {
flag|=2;
} else if ('0'<=(format1)&&(format1)<='9') {
if (digit==0 && format1=='0') {
fill='0';
} else {
digit=digit*10+((format1)-'0');
if (MAXDIGIT-2<digit) digit=MAXDIGIT-2;
}
} else if (format1=='-') {
minus=1;
} else if (format1=='d') {
flag|=4;
radix=10;
} else if (format1=='u') {
radix=10;
} else if (format1=='x') {
radix=16;
} else if (format1=='X') {
radix=16;shift=16;
} else if (format1=='o') {
radix=8;
} else if (format1=='b') {
radix=2;
} else if (format1=='p') {
radix=16;shift=16;digit=8;fill='0';flag|=2;
} else if (format1=='c') {
device_putchar((unsigned char)(va_arg(arg_ptr,int)));
flag=0;
} else if (format1=='s') {
if (digit) {
cntr=0;ptr=va_arg(arg_ptr,char *);
while (ptr[cntr]) cntr++; /*cntrは文字数*/
if (!minus) for (i=cntr;i<digit;i++) device_putchar(' ');
device_puts(ptr);
if (minus) for (i=cntr;i<digit;i++) device_putchar(' ');
} else {
device_puts(va_arg(arg_ptr,char *));
}
flag=0;
} else {
device_putchar(format1);
flag=0;
}
if (radix) {
switch (flag&6) {
case 0: /* unsig int */
value=(unsigned int)va_arg(arg_ptr,int);
break;
case 2: /* unsig long int */
value=va_arg(arg_ptr,long int);
break;
case 4: /* sig int */
value=(long int)va_arg(arg_ptr,int);
if ((long int)value<0) {
value=-(long int)value;
sign='-';
}
break;
case 6: /* sig long int */
value=va_arg(arg_ptr,long int);
if ((long int)value<0) {
value=-(long int)value;
sign='-';
}
break;
default:
break;
}
while (value) {
*ptr--=hexstring[value%radix+shift];
cntr++;
value/=radix;
}
if (cntr==0) {
*ptr--='0';
cntr++;
}
if (fill==' ') {
if (sign=='-') {
*ptr--='-';
cntr++;
}
if (!minus) for (i=cntr;i<digit;i++) device_putchar(' ');
device_puts(++ptr);
if (minus) for (i=cntr;i<digit;i++) device_putchar(' ');
} else {
for (;cntr<digit-1;cntr++) *ptr--='0';
if (sign!='-'&&cntr<digit) *ptr--='0';
else if (sign=='-') *ptr--='-';
device_puts(++ptr);
}
flag=0;
}
}
format++;
}
/*va_end(arg_ptr);*/
}
void Usart1_printf(char *format,...)
{
va_list arg;
va_start(arg, format);
Device_printf(1, format, arg);
va_end(arg);
}