1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
一、认识其本质
(一)串口
打开打开USATT1、GPIOA、AFIO的时钟 void usart_config() { /*打开USATT1、GPIOA、AFIO的时钟*/ RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); /*配置对应的串口引脚*/ usart_release_gpio_init(); /*配置串口中断*/ usart_para_config(); USART_ClearFlag(USART1,USART_FLAG_TC); //清除发送完成标志位 NVIC_Config(); //初始化NVIO USART_Cmd(USART1, ENABLE); //使能串口1 } 配置相应的IO口,将其设为复用推挽输出和浮空输入 void usart_release_gpio_init() { GPIO_InitTypeDef GPIO_InitStruct; /*配置PA9为复用推外输出*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); /*配置PA10为浮空输入*/ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStruct); } 配置NVIC(Nested Vectored Interrupt Controller),即内嵌向量中断控制器,它是用来配置中断抢占优先级和从优先级(响应优先级)的 关于抢占优先级和响应优先级区别: 高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行; void NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; //NVIC 初始化结构体声明 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //设置串口1 中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级为0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能 NVIC_Init(&NVIC_InitStructure); } 配置串口协议 void usart_para_config(void) { USART_InitTypeDef USART_InitStruct; USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_InitStruct.USART_WordLength = USART_WordLength_8b;//8 USART_InitStruct.USART_Parity = USART_Parity_No; //N USART_InitStruct.USART_StopBits = USART_StopBits_1; //1 USART_Init(USART1, &USART_InitStruct); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能接收中断 } 五、发送函数 (一)单字节发送 在main函数中调用USART_SendData(USART1, 0x08);这个函数就能够完成单字节的发送了 #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "timer.h" #include "usart.h" int main() { SystemInit(); //初始化系统,系统时钟设定为72MHz systick_init(72); //配置systick,中断时间设置为72000/72000000 = 1us usart_config(); while(1) { USART_SendData(USART1, 0x08); delay_ms(100); } } 打开串口助手就能够看到串口发来的数据了 (二)数据流发送 数据流简单来说就是一串连续的信息序列,一串序列中有若干个字节,每个字节分别对应着通信双方预先约定好的数据含义,例如第一位代表地址、第二位代表数据流向、最后一位代表结束标志、其余位代表数据。数据流的长度可长可短,由通信双方确定,但通信的过程中不能够变化。 定义一个协议栈 typedef struct { u8 head; u8 tail; u8 direction; u8 data[4]; }send_stack; send_stack tx_stack; void tx_stack_init() { tx_stack.head = 0xaa; //协议栈头,起始位,1010 1010b tx_stack.direction = 0x09;//数据流方向,0x09表示从单片机发出 memset(tx_stack.data, 0, sizeof(tx_stack.data));//把tx_stack.data[]全部初始化为零 tx_stack.tail = 0xdd; //协议栈尾,结束位,1101 1101b,栈头和栈尾最好能互补 } 将协议栈内的数据依次发出 void usart_senddata() { u8 i; while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); USART_SendData(USART1, tx_stack.head); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); USART_SendData(USART1, tx_stack.direction); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); for(i = 0; i < 4; i++) { USART_SendData(USART1, tx_stack.data); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } USART_SendData(USART1, tx_stack.tail); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } 打开串口助手可以看到串口发来的数据流 六、接收函数 接收函数和发送函数类似,先定义接收协议栈 typedef struct { u8 head; u8 tail; u8 direction; u8 data[4]; u8 lock_flag; u8 data_pt; }receive_stack; receive_stack rx_stack; void rx_stack_init() { rx_stack.head = 0x00; //协议栈头,起始位 rx_stack.direction = 0x00; //数据流方向,0x09表示从单片机发出 memset(rx_stack.data, 0, sizeof(rx_stack.data));//把tx_stack.data[]全部初始化为零 rx_stack.tail = 0x00; //协议栈尾,结束位 rx_stack.data_pt = 0x00; rx_stack.lock_flag = UNLOCK; } 接收数据需要借助中断来完成 void USART1_IRQHandler(void) { u8 receive_data; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判断读寄存器是否非空 { receive_data = USART_ReceiveData(USART1); //接收单个字节的串口数据 if(rx_stack.lock_flag == UNLOCK) //如果接收协议栈未锁柱 { if(receive_data == 0xaa) { rx_stack.head = receive_data; } else if(receive_data == 0xf9) { rx_stack.direction = receive_data; } else if(receive_data == 0xdd) { rx_stack.tail = receive_data; if(rx_stack.data_pt >= 4)// && (rx_stack.tail == 0xdd)) { rx_stack.data_pt = 0; rx_stack.lock_flag = LOCK; } } else { rx_stack.data[rx_stack.data_pt] = receive_data; rx_stack.data_pt++; if(rx_stack.data_pt > 4)// && (rx_stack.tail == 0xdd)) { rx_stack.data_pt = 0; rx_stack.lock_flag = LOCK; } } } USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接受中断标志 } } 将接收到的数据流进行解析,用灯的亮灭将控制命令现实化 void ptr_handle(u8 *stack) { u8 *stack_pt; stack_pt = stack; if(*stack_pt == 0xff) { key0.key_change_bit = CHGE_IN; if((key0.led_on_off % 2) == 1) { } else { key0.led_on_off = key0.led_on_off >=3 ? 0 : key0.led_on_off + 1; } } else { key0.key_change_bit = CHGE_IN; if((key0.led_on_off % 2) == 1) { key0.led_on_off = key0.led_on_off >=3 ? 0 : key0.led_on_off + 1; } else { } } stack_pt ++; if(*stack_pt == 0xff) { key1.key_change_bit = CHGE_IN; if((key1.led_on_off % 2) == 1) { } else { key1.led_on_off = key1.led_on_off >=3 ? 0 : key1.led_on_off + 1; } } else { key1.key_change_bit = CHGE_IN; if((key1.led_on_off % 2) == 1) { key1.led_on_off = key1.led_on_off >=3 ? 0 : key1.led_on_off + 1; } else { } } stack_pt ++; if(*stack_pt == 0xff) { key2.key_change_bit = CHGE_IN; if((key2.led_on_off % 2) == 1) { } else { key2.led_on_off = key2.led_on_off >=3 ? 0 : key2.led_on_off + 1; } } else { key2.key_change_bit = CHGE_IN; if((key2.led_on_off % 2) == 1) { key2.led_on_off = key2.led_on_off >=3 ? 0 : key2.led_on_off + 1; } else { } } stack_pt ++; if(*stack_pt == 0xff) { key3.key_change_bit = CHGE_IN; if((key3.led_on_off % 2) == 1) { } else { key3.led_on_off = key3.led_on_off >=3 ? 0 : key3.led_on_off + 1; } } else { key3.key_change_bit = CHGE_IN; if((key3.led_on_off % 2) == 1) { key3.led_on_off = key3.led_on_off >=3 ? 0 : key3.led_on_off + 1; } else { } } rx_stack.lock_flag = UNLOCK; } 主函数要做的,就是循环判断是否有灯的状态需要改变,每次接收到上位机发来的命令后把当前的状态发送到上位机 #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "timer.h" #include "gpio_config.h" #include "usart.h" int main() { SystemInit(); //初始化系统,系统时钟设定为72MHz systick_init(72); //配置systick,中断时间设置为72000/72000000 = 1us led_gpio_init(); usart_config(); tx_stack_init(); while(1) { if (key0.key_change_bit == CHGE_IN) { if((key0.led_on_off % 2) == 1) { LED0_ON; //打开LED0 tx_stack.data[0] = 0xff; } else { LED0_OFF; //关闭LED0 tx_stack.data[0] = 0x00; } key0.key_change_bit = NO_CHGE; } if (key1.key_change_bit == CHGE_IN) { if((key1.led_on_off % 2) == 1) { LED1_ON; //打开LED1 tx_stack.data[1] = 0xff; } else { LED1_OFF; //关闭LED1 tx_stack.data[1] = 0x00; } key1.key_change_bit = NO_CHGE; } if (key2.key_change_bit == CHGE_IN) { if((key2.led_on_off % 2) == 1) { LED2_ON; //打开LED2 tx_stack.data[2] = 0xff; } else { LED2_OFF; //关闭LED2 tx_stack.data[2] = 0x00; } key2.key_change_bit = NO_CHGE; } if (key3.key_change_bit == CHGE_IN) { if((key3.led_on_off % 2) == 1) { LED3_ON; //打开LED3 tx_stack.data[3] = 0xff; } else { LED3_OFF; //关闭LED3 tx_stack.data[3] = 0x00; } key3.key_change_bit = NO_CHGE; usart_senddata(); } if(rx_stack.lock_flag == LOCK) { ptr_handle(rx_stack.data); //运行协议解析函数 } } } 七、串口打印,重定向printf函数
然后在usart,c中编写字符写入函数,将格式化后的字符串依次写入到发送总线上 int fputc(int ch, FILE *f) { while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET) { } USART_SendData(USART1, (uint8_t) ch); return ch; } 在主函数中调用printf函数,实现格式化输出 #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "timer.h" #include "usart.h" int main() { SystemInit(); //初始化系统,系统时钟设定为72MHz systick_init(72); //配置systick,中断时间设置为72000/72000000 = 1us led_gpio_init(); usart_config(); tx_stack_init(); while(1) { printf("Hello World!n%dnn", 12345); delay_ms(100); } }
代码链接 回到顶部 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1780 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1081 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1679 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
596浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
556浏览 3评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 23:50 , Processed in 0.803222 second(s), Total 78, Slave 62 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号