298|7

1027

帖子

3

资源

纯净的硅(中级)

【GD32E503评测】 简易示波器实验项目总结 [复制链接]

    首先感谢兆易创新公司和EEWORLD论坛提供了这次评测的机会。我的评测计划是将ADC转换的数据以图形方式动态显示在TFT屏幕上,完成一个简易的示波器实验。本次评测用了近两个月的时间,重点进行了简易示波器的实验,通过反复探索和试验,基本上完成了项目目标,实现了以图形方式动态显示ADC转换的数据。

 

    一、TFT屏幕显示的操作

 

    了解和掌握TFT显示屏的操作是动态图形显示的第一步。通过对示例代码的分析,初步了解到屏幕显示字符是通过逐点写入的方式进行的,这为后面动态图形显示ADC转换结果打下了基础。在测试过程中发现,尽管逐点写入的效率很低,但因单片机的其他处理任务也不多,测试中并未出现显示迟滞情况。示例提供的字符显示函数功能是显示单个字符,我在此基础上改写了一个可以显示字符串的函数,同时还添加了汉字字符集,实现了汉字和ASCII码字符的混合显示。之后还添加了一个以十进制方式显示数据的函数,方便显示ADC转换的结果。下图为TFT屏幕显示的效果:

ADC0_1.jpg

    这是显示字符串的函数代码:

/*!
    \brief      从根据指定位置开始在液晶屏上显示字符串(8*16ASCII和16*16汉字字符集)
    \param[in]  x: the start position of row-coordinate    X坐标
    \param[in]  y: the start position of column-coordinate Y坐标
    \param[in]  text: the char                             要显示的字符串
    \param[in]  char_color: the color of char              字符颜色
    \param[in]  c_format: the structure of char format     字体(字库)
                  font: CHAR_FONT_8_16 or CHAR_FONT_16_24
                  direction: CHAR_DIRECTION_HORIZONTAL or CHAR_DIRECTION_VERTICAL
                  char_color: the color of char
                  bk_color: the color of background
    \param[out] none
    \retval     none
*/
void lcd_strue_display(uint16_t x,uint16_t y,uint8_t *str,char_format_struct c_format)
{
    uint8_t i,j,k,temp_char;
	uint16_t X,Y;
	X = x;
	Y = y;
	while(*str){
        if(((uint8_t)(*str)) < 128){   //显示单字节ASCII(8*16)
            if(*str > 31){
				if(CHAR_DIRECTION_HORIZONTAL == c_format.direction){//水平显示
                    for (i = 0; i < 16; i++) { //显示16行的点阵
                        temp_char = ascii_8x16[((*str - 0x20) * 16) + i];
                        for (j = 0; j < 8; j++) {
                            if (((temp_char >> (7 - j)) & 0x01) == 0x01) {
                                lcd_point_set(X - i, Y + j, c_format.char_color);
                            } else {
                                lcd_point_set(X - i, Y + j, c_format.bk_color);
                            }
                        }
                    }
					Y += 8;
			    }else{
				    for (i = 0; i < 16; i++) { //显示16行的点阵
                        temp_char = ascii_8x16[((*str - 0x20) * 16) + i];
                        for (j = 0; j < 8; j++) {
                            if (((temp_char >> (7 - j)) & 0x01) == 0x01)
                                lcd_point_set(X + j, Y + i, c_format.char_color);
                            else
                                lcd_point_set(X + j, Y + i, c_format.bk_color);
                        }
                    }
		    		X += 8;
				}

            }
			str++;
		}
		else{                          //显示双字节汉字(16*16)
		    for(k=0; k<200; k++){      //在汉字字符集中查找小于200次
			    if((GB_16ID[k][0] == *(str)) && (GB_16ID[k][1] == *(str + 1))){
					if(CHAR_DIRECTION_HORIZONTAL == c_format.direction){  //水平显示
                		for( i=0; i<16; i++){//显示16行的点阵(左半边)
                            temp_char = GB_16[(k * 32) + i];
                            for (j = 0; j < 8; j++) {
                                if (((temp_char >> (7 - j)) & 0x01) == 0x01)
                                    lcd_point_set(X - i, Y + j, c_format.char_color);
                                else
                                    lcd_point_set(X - i, Y + j, c_format.bk_color);
                            }
                        }
			            for( i=0; i<16; i++){//显示16行的点阵(右半边)
                            temp_char = GB_16[(k * 32) + i + 16];
                            for (j = 0; j < 8; j++) {
                                if (((temp_char >> (7 - j)) & 0x01) == 0x01)
                                    lcd_point_set(X - i, Y + j + 8, c_format.char_color);
                                else
                                    lcd_point_set(X - i, Y + j + 8, c_format.bk_color);
                            }
                        }
						Y += 16;
			    	} else {
                		for( i=0; i<16; i++){//显示16行的点阵(左半边)
                            temp_char = GB_16[(k * 32) + i];
                            for (j = 0; j < 8; j++) {
                                if (((temp_char >> (7 - j)) & 0x01) == 0x01)
                                    lcd_point_set(X + j, Y + i, c_format.char_color);
                                else
                                    lcd_point_set(X + j, Y + i, c_format.bk_color);
                            }
                        }
			            for( i=0; i<16; i++){//显示16行的点阵(右半边)
                            temp_char = GB_16[(k * 32) + i + 16];
                            for (j = 0; j < 8; j++) {
                                if (((temp_char >> (7 - j)) & 0x01) == 0x01)
                                    lcd_point_set(X + j + 8, Y + i, c_format.char_color);
                                else
                                    lcd_point_set(X + j + 8, Y + i, c_format.bk_color);
                            }
                        }
						X += 16;
					}
				}
			}
			str += 2;
		}
	}
}

 

    这是显示变量的函数代码:

/*!
    \brief      从指定位置开始在液晶屏上显示变量(8*16ASCII十进制数字)
    \param[in]  x: the start position of row-coordinate    X坐标
    \param[in]  y: the start position of column-coordinate Y坐标
    \param[in]  len:  显示的长度(位数,<8位)
    \param[in]  pont: 小数位数
    \param[in]  text: the char                             要显示的字符串
    \param[in]  char_color: the color of char              字符颜色
    \param[in]  c_format: the structure of char format     字体(字库)
                  font: CHAR_FONT_8_16 or CHAR_FONT_16_24
                  direction: CHAR_DIRECTION_HORIZONTAL or CHAR_DIRECTION_VERTICAL
                  char_color: the color of char
                  bk_color: the color of background
    \param[out] none
    \retval     none
*/
void lcd_value_display(uint16_t x,uint16_t y,uint8_t len, uint8_t pont, uint32_t val,char_format_struct c_format)
{
    uint8_t i,j,f = 32;           //列循环、字循环、显示标志
    uint8_t cha[] = "0000000000"; //10位
	uint32_t t,cid;               //当前余数、当前数字
	uint32_t n;                   //当前倍数

    t = val;
    n = 1;
	i = 0;
    for (j = 0; j < len; j++)
        n = n * 10;   
    
	for (j = len; j > 0; j--)     //字符循环开始
    {
        n = j < 2 ? 1: n / 10;    //计算当前的倍数
        cid = t / n;              //当前位数字
        t = t - (cid * n);
		if((cid>0) | (j-1==pont)) //有效数据后的零显示
			f = 48;
		cha[i++] = cid + f;
        if(pont > 0 & pont == (j - 1)){
			cha[i++] = 46;        //加小数点
		}
    }
	cha = 0;
	lcd_strue_display( x, y, cha, c_format);
}

 

 

    二、简易示波器实验的过程

 

    首先测试了ADC转换。利用了板上的ADC1(PA1)和ADC2(PA2),开发板上ADC1已经连接了一个多圏电位器,PA2则是通过JP4外接信号源。我制作了一个电位器扩展板作ADC2的信号源,同时还利用线性电源变换器引出低压交流电源,经过二极管半波整流后作测试动态波形的信号源。下图为ADC2连接电位器扩展板:

vawe_1.gif

    这是ADC2连接自制的低压交流(半波整流)信号源:

vawe_01.jpg

 

    在测试ADC转换的基础上继续进行了简易示波器的实验。我将2/3左右的屏幕设置成了图形显示区域,有独立和合并两种显示模式,通过按下KEY_CET进行切换。下图为独立模式,即两个ADC转换结果分别在两个区域显示,ADC1用红色线条在上部区域显示,ADC2用蓝色线条在下部区域显示。

vawe_15.jpg

    合并模式的显示效果如下图,即两组转换结果在同一个坐标系中显示,这样更容易进行比较:

vawe_14.jpg

    我在简易示波器实验中设置了三个参数可供调整,即采样率、刷新率和缩放率。调节参数时先通过KEY_A按键切换要调节的参数,然后按KEY_B或KEY_D键调节参数的大小。

    首先是采样率参数,起初准备利用定时器来触发采样,但经过多次尝试,定时器都没有设置成功,无奈只好设置了一个变量通过在主循环中对这个变量计数,达到设定值时触发采样,通过改变设定值从而改变采样率,如下图所示,在本次实验中,这个参数从50~1500每隔50为一档。经试验,参数为50时,采样率大约每秒11000多次;参数为1500时,采样率大约为每秒400次左右。

vawe_12.jpg

    第二项可调节的参数是刷新率,这个参数从5~200每隔5为一档。当参数为5时,每秒大约显示83列,3秒左右才刷新完一屏;当参数为200时,每秒大约显示15列,约16秒左右才刷新完一屏。

vawe_16.jpg

    第三项可调节的参数是缩放率。我们知道的12位ADC转换数据最大为4096,而在本次实验中,独立显示时列向为100点,合并显示时列向为200点,需要将这个数据缩小以便能显示在屏幕中,这个参数从15~40可调节(参见下图):

vawe_13.jpg

 

    三、简易示波器实验的结果

 

    开始实验时,我将ADC采样和图形显示同步进行,即随采随显。测试时,旋动电位器时,显示的线条会随同上下移动,取得了比较好的效果。但我用低压交流电经半波整流后作信号源,却看不到预期的半个正弦波,只是看到周期性变化的近似直线的波形(参见下图),看起来似乎是刷新过快的效果:

vawe_17.jpg

    在此基础上,我尝试将刷新率减少到每秒15列左右时,可以看到阶梯状的近似半个正弦波,如下图所示:

vawe_18.jpg

 

    我们知道,市电的频率为50Hz,也就是20毫秒为一个周期,而我实验时完成半个波形显示则花费了十多秒,至少过去了200多个周期。因此,上面的波形不会是真正抓取到的正弦波,也许是正好与交流电周期的“谐波”图形罢了。

    在改进的实验中,我将ADC转换与图形显示分割,ADC转换的结果放在一个数组中,显示时则从这个数组中取数据。由于显示速度比较慢,且显示一个屏幕只需要238组数据,我采取ADC转换300组数据后即暂停,等待显示完整屏后再读取300组数据继续显示。为了能显示出交流电的半个正弦波,我设想每秒采样2000次左右,一个周期采样50次,这样应该能显示出半个波形了,但事与愿违,看到的仍旧是周期性变化的水平线。

vawe_19.jpg

 

    进一步分析,觉得也许是触发ADC转换后到读取数据之间的间隙太短,造成数据不正确。于是便在触发ADC转换后插入一个延时,然后再读取数据。然而实验仍未成功,我将延时从几十微秒逐步调整到几毫秒,仅仅是水平线的变化幅度改变而已,连阶梯状的波形都没有出现过。

    通过近二十天的测试,想观看市电交流正弦波图形的努力终未成功。究其原因,可能还是ADC转换的速度问题,当然,显示屏的瓶颈问题也是重要原因。看来直接利用单片机制作示波器的设想还是不现实的,采样部分应该使用专用芯片,显示部分也不能用本次评测的显示屏。尽管本次简易示波器的实验不完全成功,但对GD32E503V-EVAL开发板的评测还是挺有收获的,这是我首次接触触摸屏,首次实现了在TFT屏幕上动态显示图形。

 

 

 

赞赏

1

查看全部赞赏


回复

1027

帖子

3

资源

纯净的硅(中级)

这是合并显示的动画:

vawe_6a.gif

 

这是独立显示的动画:

vawe_6b.gif

这是降低刷新率的动画效果:

vawe_6c.gif

这是本次实验的总结: GD32E503评测报告.rar (11.73 MB, 下载次数: 2)


回复

3349

帖子

1

资源

五彩晶圆(初级)

用emwin试试,或者移植threadx的gui,我用过emwin做个光谱的东西,感觉速度还行。

点评

谢谢建议!改天有空时试试emwin看看。  详情 回复 发表于 2021-2-24 13:34
个人签名人已离开,无事别找,找也找不到。

回复

1027

帖子

3

资源

纯净的硅(中级)

freebsder 发表于 2021-2-23 22:15 用emwin试试,或者移植threadx的gui,我用过emwin做个光谱的东西,感觉速度还行。

谢谢建议!改天有空时试试emwin看看。


回复

58

帖子

0

资源

一粒金砂(中级)

前面有其他网友实测说是能达到每秒30帧,你要不要一鼓作气解决刷新率的问题?

(肯定不是AD采样速率问题,你可以尝试先显示预先存在数组里的人造动态数据)

点评

您的建议启发了我,是应该先用预设的数据来测试显示部分,这样就能排除ADC的采样问题。  详情 回复 发表于 2021-2-26 09:44

回复

1027

帖子

3

资源

纯净的硅(中级)

mig29 发表于 2021-2-25 23:10 前面有其他网友实测说是能达到每秒30帧,你要不要一鼓作气解决刷新率的问题? (肯定不是AD采样速率问题 ...

您的建议启发了我,是应该先用预设的数据来测试显示部分,这样就能排除ADC的采样问题。


回复

824

帖子

2

资源

版主

还是非常棒的!能达到这种效果已经不错了!鼓励一下!

点评

谢谢版主鼓励!  详情 回复 发表于 2021-2-28 14:23

回复

1027

帖子

3

资源

纯净的硅(中级)

w494143467 发表于 2021-2-28 10:34 还是非常棒的!能达到这种效果已经不错了!鼓励一下!

谢谢版主鼓励!


回复
您需要登录后才可以回帖 登录 | 注册

最新文章 更多>>
    关闭
    站长推荐上一条 1/4 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2021 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表