一、串口发送
1.初始化引脚
void Serial_Init(uint32_t BaudRate)
{RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA ,ENABLE );RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1 ,ENABLE );GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;//由于PIN9为TX,故初始化为发送引脚GPIO_InitStructure.GPIO_Pin =GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;GPIO_Init (GPIOA ,&GPIO_InitStructure);USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate=BaudRate;USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//无硬件流控USART_InitStructure.USART_Mode=USART_Mode_Tx;//引脚初始化为发送模式USART_InitStructure.USART_Parity=USART_Parity_No;//无奇偶校验USART_InitStructure.USART_StopBits=USART_StopBits_1;//停止位为1位USART_InitStructure.USART_WordLength=USART_WordLength_8b;//字长位8bit即没有校验位USART_Init(USART1,&USART_InitStructure);USART_Cmd(USART1,ENABLE);//USART硬件使能
}
2.写发送函数
1.发送一个字节
每次对DR寄存器的写操作会清空TXE标志位,故不需要手动清除。
void Serial_SendByte(uint8_t data)
{USART_SendData(USART1,data);//通过DR寄存器发送一个字节while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//等待TDR位空再发送下一个字节的数据,TDR的写命令会自动清除TXE标志位
}
2.发送一个数组
void Serial_SendArry(uint8_t *arry,uint8_t length)
{for(int i=0;i<length;i++){Serial_SendByte(arry[i]);}
}
3.发送一个字符串
void Serial_String(char* String)
{for(int i =0;String[i]!=0;i++){Serial_SendByte(String[i]);}
}
4.发送数字
void Serial_SendNum(uint16_t Num)
{uint16_t weishu=1+log10(Num);uint8_t data=0;uint16_t chushu=0;for(int i = weishu-1;i>=0;i--){chushu=(uint16_t) pow(10,i );data=Num/chushu;Num=Num%chushu;Serial_SendByte(data+0x30);}
}
5.printf重定向
这里需要注意,需要在魔术棒中勾上相关选项
//重写fputc函数
int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}
二、串口接收
1.轮询方式接收数据
即在主循环中不断查询DR寄存器中的RXNE标志位是否被置为,若被置位,则说明有数据被接收,此时便可以使用USART_ReceiveData()函数去取数据。同样,对DR寄存器的读操作也会被清零。故不需要手动清零。
while(1){if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){data=USART_ReceiveData(USART1);printf("data=%d\r\n",data);}}
2.中断方式接收数据
1.在初始化中加入与中断相关的函数
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);NVIC_InitTypeDef usart_InitStructure;usart_InitStructure.NVIC_IRQChannel=USART1_IRQn;usart_InitStructure.NVIC_IRQChannelCmd=ENABLE;usart_InitStructure.NVIC_IRQChannelPreemptionPriority=2;usart_InitStructure.NVIC_IRQChannelSubPriority=2;NVIC_Init(&usart_InitStructure);
2.写中断函数以及相关接口函数
uint8_t Serial_GetFlag(void)
{if(Rxflag==1){Rxflag=0;return 1;}elsereturn 0;
}
uint8_t Serial_GetData(void)
{return Rxdata;
}
void USART1_IRQHandler(void)
{if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){Rxdata=USART_ReceiveData(USART1);Rxflag=1;}
}
3.主函数
while(1){if(Serial_GetFlag()==1){printf("data=%d\r\n",Serial_GetData());}}
}
4.或者直接在中断中输出也可以
void USART1_IRQHandler(void)
{if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){printf("rxdata=%d\r\n",USART_ReceiveData(USART1));}
}
3.串口接收HEX数据包
原理就是使用状态机的方式
void USART1_IRQHandler(void)
{if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){static uint8_t status=0;static uint8_t PacketNum=0;if(status==0){if(USART_ReceiveData(USART1)==0XFF)//如果接收到了包头OXFF,则进入下一个状态{status=1;}}else if(status==1)//不断接受数据包的内容,如果接收了四个,则进入下一个状态{if(PacketNum<4){Rxdata[PacketNum]=USART_ReceiveData(USART1);PacketNum++;}elsestatus=2;}else if(status==2)//如果接收到了OXFE,则说明接收到了包尾,则将状态位以及数组个数全部清零,同时至标志位为1,允许主循环检测{if(USART_ReceiveData(USART1)==0xFE){status=0;PacketNum=0;Rxflag=1;}}}
}
while(1){if(Serial_GetFlag()==1){for(int i =0;i<4;i++){printf("Rxdata的值为[%d]=:%d\r\n",i,Rxdata[i]);}}}
}
4.串口接收文本数据包
char Rxdata[100] ;
uint8_t Rxflag;void USART1_IRQHandler(void)
{if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){static uint8_t status=0;static uint8_t PacketNum=0;if(status==0){if(USART_ReceiveData(USART1)=='@'){status=1;}}else if(status==1) {if(USART_ReceiveData(USART1)!='\r'){Rxdata[PacketNum]=USART_ReceiveData(USART1);PacketNum++;}elsestatus=2;}else if(status==2) {if(USART_ReceiveData(USART1)=='\n'){Rxdata[PacketNum]=0;//这里加上'\0',是字符串结束的标志status=0;PacketNum=0;Rxflag=1;}}}
}
while(1){if(Serial_GetFlag()==1){Serial_String(Rxdata);Serial_SendByte('\r');Serial_SendByte('\n');}}