使用STM32串口模块配合SerialChart实现虚拟示波器功能

1、硬件连接

单片机IO口配置

2、上位机系统环境

要用Windows系统,(XP 32bit亦可)。下载好SerialChart-0.3.4。

我使用的是Keil MDK 4 + STM32CubeMX。

SerialChart配置文件:

[_setup_]
port=COM9   
baudrate=115200

width=1000
height=400
background_color = white

grid_h_origin = 0
grid_h_step = 10
grid_h_color = #EEE
grid_h_origin_color = #000

grid_v_origin = 0
grid_v_step = 10
grid_v_color = #EEE
grid_v_origin_color = #000

[_default_]
min=-8
max=8

[interval]
color=transparent
min=0
max=100000

[InVolt]
color=blue

[InCurr]
color=red

[InPwr]

[OutVolt]
color=black

[OutCurr]
color=orange

[OutPwr]


[an3]
color=transparent
min=0
max=1023

[_setup_]里:port口请选择正确的COM口,打开设备管理器确认,或者打开串口调试助手(我使用的是ATK-XCOM V2.0),即可查看对应的COM口。波特率baudrate=115200,这个参数要和STM32的对应。

[_default_]是默认参数的大小。这个范围外的界面无法显示。

[interval]以及以下的就是数据的配置,数据的名称可自由配置。[interval]是第一列数据。[InVolt]是第二列数据。[InCurr]是第三列数据。以此类推。因为当时我用这个配置文件,显示输入电流、输入电压、输出电流、输出电压,所以用这个英文名字。可以随意改的,与数据显示无关系的。

我使用的数据是:第一列是时间戳,第二列开始是CH1,第三列是CH2。

例子:SerialChart会显示一包数据:20180110083138,1.2931,0.0758

扫描二维码关注公众号,回复: 3455130 查看本文章

其中第一个数据是时间戳,指当前时刻是2018年1月10日8:31:38。第二个数据是CH1=1.2931V,第三个数据是CH2=0.0758V。

另外要注意在配置ADC_DMA时候,DMA要配置成Circular才可以调用HAL_ADC_Start_DMA()。如果还是DMA Mode Normal,会进入硬件hardfault_handler。不知道为什么。

3、STM32程序

参数声明:

float b_PirRaw,b_PirFltr;
char s_PirRaw[10];
char s_PirFltr[10];

uint32_t b_date, b_month, b_year, b_hour, b_minute, b_second, b_day;
char s_time[25];
char a_date[2], a_month[2], a_year[4], a_hour[2], a_minute[2], a_second[2];

3.1 main主函数:

int main(void)
{

  while (1)
  {

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
        if(flag_100ms==1)
	{
	    flag_100ms=0;
	    SerialDisplay();        //数据通过串口发送出去
	}
        if(flag_1s==1)
        {    
            flag_1s=0;
            UpdateDateTime();        //更新时间
        }
  }
  /* USER CODE END 3 */

}

3.2 SerialDisplay():


void SerialDisplay(void)
{
    s_time[0] = a_year[0];
    s_time[1] = a_year[1];
    s_time[2] = a_year[2];
    s_time[3] = a_year[3];
    s_time[4] = a_month[0];
    s_time[5] = a_month[1];
    s_time[6] = a_date[0];
    s_time[7] = a_date[1];
    s_time[8] = a_hour[0];
    s_time[9] = a_hour[1];
    s_time[10] = a_minute[0];
    s_time[11] = a_minute[1];
    s_time[12] = a_second[0];
    s_time[13] = a_second[1];
    s_time[14] = '\0';
		
    float2str(b_PirRaw, 2, s_PirRaw);    //将float转换为str
    float2str(b_PirFltr, 2, s_PirFltr);    //将float转换为str

    strcpy(a_UartTxBuf, s_time);        //将s_time复制至a_UartTxBuf
    strcat(a_UartTxBuf, ",");           //这句语句效果是a_UartTxBuf += ","
    strcat(a_UartTxBuf, s_PirRaw);      //这句语句效果是a_UartTxBuf += s_PirRaw
    strcat(a_UartTxBuf, ",");  
    strcat(a_UartTxBuf, s_PirFltr);
    strcat(a_UartTxBuf, "\r\n");        //一个数据包的结尾是"\r\n",同时strlen计算字符串长度是计算到\r\n
  
    HAL_UART_Transmit(&huart1, (uint8_t*)a_UartTxBuf, strlen(a_UartTxBuf), 100);	//发送数据
	
}

以上转换时间那几行真的不怎么优雅……

3.3 float2str

浮点数转换字符串。这代码我是复制的,来自https://www.cnblogs.com/gleam/p/3607984.html

/**
  * @brief  convert float to string
  * @param  
  * @usage  char buf[128]; 
  *					printf("%s\n", float2str((float)1234.56789, -2, buf)); 
  * @retval None
  */
char * float2str(float val, int precision, char *buf)
{
    char *cur, *end;
    
    sprintf(buf, "%.4f", val);
    if (precision < 4) {
        cur = buf + strlen(buf) - 1;
        end = cur - 4 + precision; 
        while ((cur > end) && (*cur == '0')) {
            *cur = '\0';
            cur--;
        }
    }
    
    return buf;
}

3.4 UpdateDateTime

每秒要执行一次这代码,更新本机时间。


/*
 * @brief UpdateDateTime
 * input param: none
 * output param: none
 * relevent param: b_date b_month b_year b_hour b_minute b_second
 * must be execute every 1 second
 */
void UpdateDateTime(void)
{
	b_second++;
	if(b_second>=60)
	{
		b_second = 0;
		b_minute++;
		if(b_minute>=60)
		{
			b_minute = 0;
			b_hour++;
			if(b_hour>=24)
			{
				b_hour = 0;
				b_date++;
				if((b_date>=29)&&(b_month==2))
				{
					b_date = 0;
					b_month++;
				}
				else if((b_date>=31)&&((b_month==4)||(b_month==6)||(b_month==9)||(b_month==11)))
				{
					b_date = 0;
					b_month++;
				}
				else if((b_date>=32)&&((b_month==1)||(b_month==3)||(b_month==5)||(b_month==7)||(b_month==8)||(b_month==10)||(b_month==12)))
				{
					b_date = 0;
					b_month++;
					if(b_month>=13)
					{
						b_month = 0;
						b_year++;
					}
				}
			}
		}
	}

	a_year[0] = b_year/1000 + '0';
	a_year[1] = b_year%1000/100 + '0';
	a_year[2] = b_year%100/10 + '0';
	a_year[3] = b_year%10 + '0';

	a_month[0] = (uint8_t)b_month/10 + '0';
	a_month[1] = (uint8_t)b_month%10 + '0';

	a_date[0] = (uint8_t)b_date/10 + '0';
	a_date[1] = (uint8_t)b_date%10 + '0';

	a_hour[0] = (uint8_t)b_hour/10 + '0';
	a_hour[1] = (uint8_t)b_hour%10 + '0';

	a_minute[0] = (uint8_t)b_minute/10 + '0';
	a_minute[1] = (uint8_t)b_minute%10 + '0';

	a_second[0] = (uint8_t)b_second/10 + '0';
	a_second[1] = (uint8_t)b_second%10 + '0';

}

4、显示效果

以上看到本程序使用的数据包格式是:

<Timestramp>,<ch1>,<ch2>\r\n

即实现了带时间戳的双通道数据显示。

如果需要显示4通道,可以按照这样的格式:

<Timestramp>,<ch1>,<ch2>,<ch3>,<ch4>\r\n

如果需要显示更多的数据,可以按照这样的格式:

<Timestramp>,<ch1>,<ch2>,<ch3>,<ch4>,<ch5>,<ch6>,...,<chn>\r\n

也可以不发送第一列时间戳,但要在配置文件中删除[interval]

共享了工程:

链接: https://pan.baidu.com/s/1CQk6l4ziFMHXGxQEBbF_OA 提取码: aey4

猜你喜欢

转载自blog.csdn.net/qq_27158179/article/details/82866451