7.串口LDIE的不定长接收
(1)将时钟树配置为32MHz
(2)Cubemx的配置
将第五个实验的文件夹复制后进入Cubemx中进行图中配置即可生成项目
(3)keil代码的生成
需要在stm32l0xx_it.c文件中添加如下内容
Final.c
#include "Final.h"
#include "gpio.h"
#include "string.h"
#include "stdio.h"
#define final_uart_rx_buffer_len 100//允许不定长接收的数据的缓存区长度
unsigned char final_uart_rx_len;//接收到一帧串口数据的长度
unsigned char final_uart_rx_end_flag;//接收到一帧串口数据接收时的标志位
unsigned char final_uart_rx_buffer[final_uart_rx_buffer_len];//接收数据缓存数组
extern UART_HandleTypeDef huart2;//申明句柄
extern DMA_HandleTypeDef hdma_usart2_rx;//申明句柄
void Final_LD5(unsigned char state)
{
switch(state)
{
case 0:
HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_SET);
break;
case 1:
HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_RESET);
break;
case 2:
HAL_GPIO_TogglePin(LD5_GPIO_Port, LD5_Pin);
break;
}
}
void Final_Relay(unsigned char number,unsigned char state)
{
switch(number)
{
case 1:
switch(state)
{
case 0:
HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_RESET);
break;
case 1:
HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_SET);
break;
case 2:
HAL_GPIO_TogglePin(K1_GPIO_Port, K1_Pin);
break;
}
break;
case 2:
switch(state)
{
case 0:
HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_RESET);
break;
case 1:
HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_SET);
break;
case 2:
HAL_GPIO_TogglePin(K2_GPIO_Port, K2_Pin);
break;
}
break;
}
}
//unsigned char Final_Key(void)
//{
// unsigned char value=0;
// if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==RESET)
// {
// HAL_Delay(20);
// if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==RESET)
// {
// value=1;
// while(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==RESET);
// }
// }
// return value;
//}
void HAL_GPIO_EXTI_Callback(unsigned short int GPIO_Pin)
{
if(GPIO_Pin==KEY_Pin)
Final_LD5(2);
}
void Final_UART_DMA_Tx(const unsigned char *final_uart_tx_data)
{
HAL_UART_Transmit_DMA(&huart2,final_uart_tx_data,strlen(final_uart_tx_data));
}
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart2,(uint8_t *)&ch,1,1000);
return ch;
}
//名称:Final_USART_IDLE_RX
//作用:串口2以中断,DMA和IDLE寄存器模式接收字符串数据
//参数:无
//返回值:无
//备注:请将该函数添加到USART2_IRQHandler中
void Final_USART_IDLE_RX(void)
{
if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE)==SET)//idle标志位被置位
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2);//清除idle标志位
HAL_UART_DMAStop(&huart2);//停止DMA传输
final_uart_rx_len=final_uart_rx_buffer_len-__HAL_DMA_GET_COUNTER(&hdma_usart2_rx);//总计数减去未传输的数据个数,得到已经接收的数据个数
final_uart_rx_end_flag=1;//串口接收完成标志位置1
}
}
void Final_USART_RX_Deal(void)
{
if(final_uart_rx_end_flag)//如果串口接收完成
{
//下面是串口数据处理的相关函数
HAL_UART_Transmit_DMA(&huart2,final_uart_rx_buffer,final_uart_rx_buffer_len);
//上面是串口数据处理的相关函数
final_uart_rx_len=0;//清除接收到一帧串口数据的长度
final_uart_rx_end_flag=0;//接收到一帧串口数据接收时的标志位
HAL_UART_Receive_DMA(&huart2,final_uart_rx_buffer,final_uart_rx_buffer_len);//重新打开DMA接收
}
}
unsigned char *Final_RTC(void)
{
static unsigned char rtc_value[7];
extern RTC_HandleTypeDef hrtc;
RTC_TimeTypeDef time_value;
RTC_DateTypeDef date_value;
HAL_RTC_GetTime(&hrtc,&time_value,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&date_value,RTC_FORMAT_BIN);
rtc_value[0]=date_value.Year;
rtc_value[1]=date_value.Month;
rtc_value[2]=date_value.WeekDay;
rtc_value[3]=date_value.Date;
rtc_value[4]=time_value.Hours;
rtc_value[5]=time_value.Minutes;
rtc_value[6]=time_value.Seconds;
return rtc_value;
}
//名称:Final_Init
//作用:初始化各个模块
//参数:无
//返回值:无
//备注:无
void Final_Init()
{
Final_LD5(0);
Final_Relay(1,0);
Final_Relay(2,0);
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE); //使能IDLE中断
HAL_UART_Receive_DMA(&huart2,final_uart_rx_buffer,final_uart_rx_buffer_len);//开启DMA接收
}
main.c
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "rtc.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "Final.h"
#include "stdio.h"
/* USER CODE END Includes */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
MX_RTC_Init();
/* USER CODE BEGIN 2 */
Final_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
Final_USART_RX_Deal();
/* USER CODE END WHILE */
(4)实验现象
打开串口发送如何内容只要不超过定义的长度都能秒发送秒接收
8.OLED的显示
(1)将时钟树配置为32MHz
(2)OLED的配置
将PB5配置为GPIO_OutPut,标签改为OLED_Power,然后将PB4和PA8分别配置为I2C3_SDA和I2C3_SCL(此时PB4和PA8为黄色的)最后点击I2C3,选择I2C生成代码即可
在生成代码后将官方给的OLED.h和OLED.c、front.h代码添加至所生成文件中core的ins和scr
最后在keil中添加OLED.c
(3)keil代码的生成
Final.c
#include "Final.h"
#include "gpio.h"
#include "string.h"
#include "stdio.h"
#include "oled.h"
#define final_uart_rx_buffer_len 100
unsigned char final_uart_rx_len;
unsigned char final_uart_rx_end_flag;
unsigned char final_uart_rx_buffer[final_uart_rx_buffer_len];
extern UART_HandleTypeDef huart2;
extern DMA_HandleTypeDef hdma_usart2_rx;
extern I2C_HandleTypeDef hi2c3;
void Final_LD5(unsigned char state)
{
switch(state)
{
case 0:
HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_SET);
break;
case 1:
HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_RESET);
break;
case 2:
HAL_GPIO_TogglePin(LD5_GPIO_Port, LD5_Pin);
break;
}
}
void Final_Relay(unsigned char number,unsigned char state)
{
switch(number)
{
case 1:
switch(state)
{
case 0:
HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_RESET);
break;
case 1:
HAL_GPIO_WritePin(K1_GPIO_Port, K1_Pin, GPIO_PIN_SET);
break;
case 2:
HAL_GPIO_TogglePin(K1_GPIO_Port, K1_Pin);
break;
}
break;
case 2:
switch(state)
{
case 0:
HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_RESET);
break;
case 1:
HAL_GPIO_WritePin(K2_GPIO_Port, K2_Pin, GPIO_PIN_SET);
break;
case 2:
HAL_GPIO_TogglePin(K2_GPIO_Port, K2_Pin);
break;
}
break;
}
}
//unsigned char Final_Key(void)
//{
// unsigned char value=0;
// if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==RESET)
// {
// HAL_Delay(20);
// if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==RESET)
// {
// value=1;
// while(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin)==RESET);
// }
// }
// return value;
//}
void HAL_GPIO_EXTI_Callback(unsigned short int GPIO_Pin)
{
if(GPIO_Pin==KEY_Pin)
Final_LD5(2);
}
void Final_UART_DMA_Tx(const unsigned char *final_uart_tx_data)
{
HAL_UART_Transmit_DMA(&huart2,final_uart_tx_data,strlen(final_uart_tx_data));
}
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart2,(uint8_t *)&ch,1,1000);
return ch;
}
void Final_USART_IDLE_RX(void)
{
if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE)==SET)
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2);
HAL_UART_DMAStop(&huart2);
final_uart_rx_len=final_uart_rx_buffer_len-__HAL_DMA_GET_COUNTER(&hdma_usart2_rx);
final_uart_rx_end_flag=1;
}
}
void Final_USART_RX_Deal(void)
{
if(final_uart_rx_end_flag)
{
HAL_UART_Transmit_DMA(&huart2,final_uart_rx_buffer,final_uart_rx_buffer_len);
final_uart_rx_len=0;
final_uart_rx_end_flag=0;
HAL_UART_Receive_DMA(&huart2,final_uart_rx_buffer,final_uart_rx_buffer_len);
}
}
//名称:OLED_Write
//作用:OLED写函数
//参数:系统函数 无需关系
//返回值:无
//备注:无
void OLED_Write(unsigned char addr,unsigned char data)
{
unsigned char pdata[2];
pdata[0]=addr;
pdata[1]=data;
HAL_I2C_Master_Transmit(&hi2c3,0x78,pdata,2,0xff);
}
//名称:Zsdz_OLED_Init
//作用:OLED用户初始化
//参数:初始化时间
//返回值:无
//备注:无
void Final_OLED_Init(unsigned char ms)
{
HAL_GPIO_WritePin(OLED_Power_GPIO_Port, OLED_Power_Pin, GPIO_PIN_RESET);
HAL_Delay(ms);
OLED_Init();
OLED_Clear();
}
unsigned char *Final_RTC(void)
{
static unsigned char rtc_value[7];
extern RTC_HandleTypeDef hrtc;
RTC_TimeTypeDef time_value;
RTC_DateTypeDef date_value;
HAL_RTC_GetTime(&hrtc,&time_value,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&date_value,RTC_FORMAT_BIN);
rtc_value[0]=date_value.Year;
rtc_value[1]=date_value.Month;
rtc_value[2]=date_value.WeekDay;
rtc_value[3]=date_value.Date;
rtc_value[4]=time_value.Hours;
rtc_value[5]=time_value.Minutes;
rtc_value[6]=time_value.Seconds;
return rtc_value;
}
void Final_Init()
{
Final_LD5(0);
Final_Relay(1,0);
Final_Relay(2,0);
Final_OLED_Init(100);
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart2,final_uart_rx_buffer,final_uart_rx_buffer_len);
}
main.c
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "i2c.h"
#include "rtc.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "Final.h"
#include "oled.h"
#include "stdio.h"
/* USER CODE END Includes */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
MX_RTC_Init();
MX_I2C3_Init();
/* USER CODE BEGIN 2 */
Final_Init();
unsigned char final_oled_buffer[16];
unsigned char *final_uart_tx_data;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
final_uart_tx_data=Final_RTC();
printf("\r\n RTC:%d-%d-%d \r\n %d:%d:%d \r\n",2000+final_uart_tx_data[0],
final_uart_tx_data[1],final_uart_tx_data[3],final_uart_tx_data[4],
final_uart_tx_data[5],final_uart_tx_data[6]);
sprintf((char *)final_oled_buffer," Date:%d-%d-%d ",2000+final_uart_tx_data[0],final_uart_tx_data[1],final_uart_tx_data[3]);
OLED_ShowString(0,final_oled_buffer);
sprintf((char *)final_oled_buffer," time:%2d:%2d:%2d ",final_uart_tx_data[4],final_uart_tx_data[5],final_uart_tx_data[6]);
OLED_ShowString(2,final_oled_buffer);
HAL_Delay(1000);
Final_USART_RX_Deal();
/* USER CODE END WHILE */
注意:因为oled中的OLED_Write是由自己写的,所以需要添加头文件,所有在自己写的.c文件中的函数都要在头文件中进行封装。
(4)实验现象
由main函数中的代码可知第一行显示日期,第二行显示时间