STM32陶晶池串口屏使用
详见快速入门 --- 淘晶驰资料中心 1.1.0-2024-07-15 23:52:37 文档 (tjc1688.com),官方文档讲解的很清晰
上位机部分
新建工程后选择对应型号
介绍一下几个上位机的函数
1.prints函数
注意prints函数串口打印变量时要加上位数,默认是0的话会发送四个字节数据
就会有三个字节都是0,不方便单片机识别
我们将位数设置为1,同时加上帧头0xaa,帧尾0x0d,中间留两个字节给数据部分,这样一串数据就是四字节
函数部分
我们需要注意的是
- 配置的波特率与上位机中要一致
- 线不要接错
同时,还可能遇到一种问题就是数据可以发送给单片机,只有第一次能收到,后续单片机无法接收
先注意下printf函数的问题,C语言中printf函数的数据是预先存放的,等到缓存堆满后再输出,或者就是遇到\n换行符直接输出,而陶晶驰这个是\ff\ff\ff做帧尾不允许有\n,我们在第一行加上
c
setbuf(stdout, NULL); // 禁用缓冲
就可以禁用缓冲区,直接printf输出了。
注意printf函数要在标志位之前放,因为printf函数可能会影响串口的正常接收,这时候如果你的串口接收中断函数写的不严谨就会出现问题。
同时,我们注意重定向的printf函数是有一个发送的最大等待延时的,如果一口气接收多帧数据,那么你的printf函数最好用在接收完最后一组数据之后再用。笔者就曾经出现过因为两帧之间用了printf函数导致第二帧接收的数据有错乱
最后附上源码
c
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define DataLength 4
#define datanum 10
#define AdcNum 5
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
volatile bool rx_data_receive = false;//串口接收标志位
extern bool get_shape_shut;
volatile uint16_t sweep_flag = 0;//扫频标志位
uint8_t rx_data_sta =0;//辅助判断接收进度变量
uint16_t rx_data_cache[1] = {0};//串口接收数据缓存
uint16_t rx_data[DataLength] = {0};//串口接收数据(毛)
uint16_t rx_data_buffer[DataLength] = {0};//串口接收数据(精)
uint16_t rx_data_sine[DataLength]={0};//点频的数据存放
uint32_t adc_buffer[2000] ={0};//未使用到
/* USER CODE END PV */
//......
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim3);
AD9854_Init();
AD9854_InitRFSK();
HAL_UART_Receive_IT(&huart1, (uint8_t *)rx_data_cache, 1);
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
if (rx_data_receive == true)
{
if (rx_data[1] == 0x09 )
{//此部分可以封装进赋值函数
rx_data_sine[0] = rx_data[0];
rx_data_receive = false;
}
else if (rx_data[1] == 0x11 )
{
rx_data_sine[1] = rx_data[0];
printf("%d",rx_data_sine[0]);
printf("%d",rx_data_sine[1]);
rx_data_receive = false;
//以下部分为点频输出语句
bsp_set_sine(rx_data_sine[0],rx_data_sine[1]);
}
else if (rx_data[1] == 0x01 )
{
rx_data_buffer[0] = rx_data[0];
rx_data_receive = false;
}
else if (rx_data[1] == 0x03 )
{
rx_data_buffer[1] = rx_data[0];
rx_data_receive = false;
}
else if (rx_data[1] == 0x05 )
{
rx_data_buffer[2] = rx_data[0];
rx_data_receive = false;
}
else if (rx_data[1] == 0x07 )
{
rx_data_buffer[3] = rx_data[0];
printf("%d,%d,%d,%d",rx_data_buffer[0],rx_data_buffer[1],rx_data_buffer[2],rx_data_buffer[3]);
rx_data_receive = false;
memset(rx_data,0, sizeof(rx_data));
//以下部分为扫频输出语句
sweep_flag = 1;
get_shape_shut = false;
}
else if (rx_data[1] == 0x15 )
{
sweep_flag = 0;
get_shape_shut = true;
AD9854_Init();
rx_data_receive = false;
}
}
/* USER CODE END WHILE */
//......
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
UNUSED(huart);
if (huart->Instance == USART1)//串口1执行接收操作
{
if (rx_data_receive == false)
{
if (rx_data_cache[0] == 0xaa)//判断是否为帧头
{
}
else if (rx_data_cache[0] == 0x0d)
{
rx_data_sta = 0;
rx_data_receive = true;
}
else if((rx_data_cache[0] != 0xaa ) && (rx_data_cache[0] != 0x0d))
{
rx_data[rx_data_sta] = rx_data_cache[0];
rx_data_sta ++;
}
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)rx_data_cache, 1);
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim ->Instance == htim3.Instance)
{
//此处为扫频输出函数
if (sweep_flag!=0)
{
bsp_set_sweep(rx_data_buffer[0],rx_data_buffer[1],rx_data_buffer[2]);
HAL_TIM_Base_Start(&htim8);
HAL_ADC_Start_DMA(&hadc1,&adc_buffer[(sweep_flag-1)*AdcNum],AdcNum);
}
}
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)//ADC中断回调函数
{
UNUSED(hadc);
HAL_TIM_Base_Stop(&htim8);
}
以上可能有部分诸如AD9854之类的函数,是无关项,可忽略
注意串口的中断回调函数中,我们先用if语句判断一个标志位,然后再判断帧头和帧尾以及帧数据的存储,这里其实改的更严谨点可以先判断帧头再帧尾最后帧数据存储。