实验板串行相关电路:
数码管等外设的电路前面的实验已经提到过,不再赘述。
使用cubeMX配置项目:
因为数码管,蜂鸣器这些外设对应的引脚在前面的项目里已经配置过,可以选择前面的一个项目,另存为,就剩去再配置外设相关引脚的功夫。如下图:
跟之前的项目配置步骤差不多, 串口通信部分的配置步骤可以看正点原子的视频(第9讲和第10讲):
【【正点原子】手把手教你学STM32CubeIDE开发】 https://www.bilibili.com/video/BV1Wp42127Cx/?p=9&share_source=copy_web&vd_source=9332b8fc5ea8d349a54c3989f6189fd3
串行口调试程序
串行口调试程序使用的sscom5.13.1,在老师发的工具文件夹里可以找到:
注意:端口的选择和数据发送的形式,图上的方框只是强调位置,并非是要选择成图里的样子。
实验内容
实验一要求
1、采用查询法编写串口程序,串行口波特率设置为 115200bps,数据字长 8 位,停止位 1 位,无校验。
(1)向串行口发送 1 个字符数据,开发板接收到数据后,将数据加一从串口发回。
(2)向串行口发送 1 个字符数据,开发板接收到数据后,判定数据为 Y 或者 y 跑马灯 全亮、数据为 N 或者 n 跑马灯全灭,其他字符,跑马灯旋转。
(3)重定向 printf、scanf 函数到串口。
这个实验很简单,这里只说(2)要求,只涉及到跑马灯的控制,写一个函数来控制:
void paoMaDeng(uint8_t flag){
uint16_t x=0x0001;
if(flag=='y'||flag=='Y'){
for(int i=0;i<8;i++){
HAL_GPIO_WritePin(GPIOF,x<<i,1);
}
}else if(flag=='n'||flag=='N'){
for(int i=0;i<8;i++){
HAL_GPIO_WritePin(GPIOF,x<<i,0);
}
}else{
for(int i=0;i<8;i++){
HAL_GPIO_WritePin(GPIOF,x<<i,1);
for(int i=0;i<1000000;i++);
HAL_GPIO_WritePin(GPIOF,x<<i,0);
}
}
}
在while里的接收语句HAL_UART_Receive后,调用这个函数即可。
while (1)
{
HAL_UART_Receive(&huart1,revbuf,sizeof(revbuf),HAL_MAX_DELAY);
//printf("%c",revbuf[0]);
//将数据加一从串口发回
//revbuf[0]+=1;
//1秒
//HAL_UART_Transmit(&huart1,revbuf,sizeof(revbuf),1000);
/*
数据为 Y 或者 y 跑马灯全亮、数据为 N 或者 n 跑马灯全灭,其他字符,跑马灯旋转
*/
paoMaDeng(revbuf[0]);
}
实验二要求:
(1)向串行口发送 1 个字符数据,开发板接收到数据后,将数据加一从串口发回。
(2)向串行口发送 1 个字符数据,开发板接收到数据后,判定数据为 Y 或者 y 跑马灯 全亮、数据为 N 或者 n 跑马灯全灭,其他字符,将数据的 ASCII 码显示在数码管上。 显示内容为 XXH。
数码管显示可以直接沿用前面实验的代码,但这里需要注意的是,前面实验的代码段码表只写了0到9的,这里需要补上A到F的,以及还需要显示H,H对应的段码是0x76。
段码表:
unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x88,0x83,0xc6,0xa1,0x86,0x8e };
为了让数码管在发送其他字符的时候一直显示,中断回调函数里不直接操作数码管进行显示,只将它的标志置1,然后主函数里的while里判断该标志,为1就进行显示,还要注意的是,中断回调函数里最后要调用一次HAL_UART_Receive_IT(&huart1,revbuf,sizeof(revbuf));以触发下次中断:
int shuMaGuan=0;
//16个字符,0-F
unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x88,0x83,0xc6,0xa1,0x86,0x8e };
unsigned char s[]={0,0,0,0,0,0,7,15};
void write_byte(unsigned char date){
unsigned char i;
for(i=0;i<8;i++){
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,(date>>(7-i))&0x01);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,1);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,0);
}
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,1);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,0);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
if(huart->Instance==USART1)
{
//revbuf[0]+=1;
//HAL_UART_Transmit_IT(&huart1,revbuf,sizeof(revbuf));
uint16_t x=0x0001;
uint8_t flag=revbuf[0];
if(flag=='y'||flag=='Y'){
shuMaGuan=0;
for(int i=0;i<8;i++){
HAL_GPIO_WritePin(GPIOF,x<<i,1);
}
}else if(flag=='n'||flag=='N'){
shuMaGuan=0;
for(int i=0;i<8;i++){
HAL_GPIO_WritePin(GPIOF,x<<i,0);
}
}else{//为了一直显示数码管,这里只操作标志,在主函数里的while循环里实现显示效果
shuMaGuan=1;
int temp=(int)revbuf[0];
s[7]=temp%16;
s[6]=temp/16%16;
}
HAL_UART_Receive_IT(&huart1,revbuf,sizeof(revbuf));
}
}
主函数中:
while (1)
{
if(shuMaGuan==1)
{
write_byte(0x76);//显示'H'
HAL_GPIO_WritePin(GPIOF,0x01<<8,0);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOF,0x01<<8,1);
for(int i=8;i<10;i++){
write_byte(table[s[15-i]]);
HAL_GPIO_WritePin(GPIOF,0x02<<i,0);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOF,0x02<<i,1);
}
}
}
实验三
3、构建发送和接收缓冲区,编写发送和接收单字节、双字节、四字节和字符串发送函数。将接收到的字符串从串口发回,并在数码管上显示你接收到的字符串。
缓冲区可以建两个10字节的数组,比8字节要大一些。需要注意的是,要约定字符串结束的符号,接收到这个符号之后,这个字符串就发送结束了,比如约定以'\0'为结束,这个结束符也占一个字节。
实验四
采用中断法定义串口通讯协议,串行口波特率设置为 115200bps,数据字长 8 位,停 止位 1 位,无校验。通过串行口向蜂鸣器、电机、跑马灯和数码管发送 5 字节命令。
因为是5字节命令,校验字节用00来占位。