基于GD32F103RET6与Matlab的串口虚拟示波器 日记

3 篇文章 0 订阅
3 篇文章 0 订阅

上一期点这里查看

1.各功能展示

测试用的是大约50KHz的方波,由Arduino Nano产生,程序如下:

void setup() {
  pinMode(6,OUTPUT);
}

void loop() {
  digitalWrite(6, HIGH);
  delayMicroseconds(10);
  digitalWrite(6, LOW);
  delayMicroseconds(10);
}

1.周期调节

 2.灵敏度调节。可以软件有损调节,也可以硬件电位器调节。这里展示的是软件调节。

3.触发

 

2.硬件部分

 

单片机部分请前往这里 查看详细制作过程。

除了单片机部分,还有ADC前的偏置电压放大电路需要制作。由于长时间不在家,库存的运放也找不到了。三极管凑活用。

电路图如下:

电阻取值计算:
 

a. 粗略取 Irc 大约 10mA,要使集电极电压大约为Vcc的 1/2, 即 1.65V,那么 Rc大约需要165欧,  随便找了个100欧的, 此时Irc为 1.65V/ 100欧 = 16.5mA。
b. 万用表测得三极管放大倍数是256倍。那么Irb = 16.5mA/256 = 64.5 uA。
c.三极管BE压降约0.7V, 则Urb = 3.3 - 0.7 =2.6V。
d . Rb = 2.6V/ 64.5uA = 40.3 K。

先搭棚焊接测试,如图:


2020-5-18更新运放电路图(358响应速度不太行,建议换成其他高速运放):

说明:

NE555产生负电压; U2A输入信号电压跟随;U2B基准电压跟随;U3A加法器,把输入信号和基准电压叠加;U3B放大,把信号放大到0~Vref。

 

 

3.程序部分

 


2020-5-18 更新,添加程序框图:

单片机部分:

Matlab 及硬件 部分:

 

 

 

 

 

程序不复杂,就是不停地采样,然后发送。由于写的很乱,没来得及整理,就暂时不发出来了。

这里说一下一些初学者容易掉坑里的地方,我也被这些地方卡了挺久的:

1.无论做什么,先使能其时钟,不然任何操作都不会生效。

举几个例子:

//要操作IO,先使能IO时钟
rcu_periph_clock_enable(RCU_GPIOA);
//要使用ADC,先使能ADC时钟
rcu_periph_clock_enable(RCU_ADC0);
//要使用串口,先使能串口时钟
rcu_periph_clock_enable(RCU_USART0);
//DAC、计时器、DMA同理,详细内容参考官方文档

 

2.中断优先级及服务函数名

a. GD32F10x 系列单片机中断优先级由 nvic 库管理,官方文档中并没有中断优先级相关内容,导致看官方给的例程时候一脸问号。

使用中断务必配置优先级。比如我用到了ADC0中断,就需要调用如下函数进行优先级配置,具体函数定义可以看nvic文档:

void nvic_config(void)
{
    nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
    nvic_irq_enable(ADC0_1_IRQn, 1, 1);
}

b. 服务函数名在启动文件 startup_gd32f10x_hd.s 中有定义,如下图

比如ADC0 的中断服务函数可以写成

void ADC0_1_IRQHandler(){
	adc_interrupt_flag_clear(ADC0, ADC_INT_EOC);//清除中断标志
	ADC_DATA[DATA_COUNT++]=adc_regular_data_read(ADC0);//记录数据
	adc_flag_clear(ADC0, ADC_FLAG_EOC);//清除转换完成标记
}

 

3.串口波特率

波特率需要一些特殊值,比如115200,921600等,可以计算得到,与时钟频率相关。不适当的波特率会导致无法通信。懒得计算也可以用已知可用值的整数倍,一般也是可用的。

4.串口传送12位的ADC数据

由于串口只能传送 8 位数,而ADC是12位的返回值,所有有两个选择。一是降低精度,二是自己写个简单的发送协议。

我采用第二种方案。

两帧 8 位数据一共 16 位, 把每帧的最后一位作为标记位, 剩余两个 7位可以用来传送 14位有效的数据。

接收端收到的 8 位二进制数据中, 最末位为 1 的是低7 位数据, 最末位为 0 的是高7 位数据,再进行拼接。

单片机(发送端)程序为:

while(usart_flag_get(USART0, USART_FLAG_TBE)==0);//等待前面的数据进入队列寄存器
usart_data_transmit(USART0,(ADC_DATA[DATA_COUNT]<<1)|0x0001);//发送低7位
while(usart_flag_get(USART0, USART_FLAG_TBE)==0);//等待前面的数据进入队列寄存器
usart_data_transmit(USART0,(ADC_DATA[DATA_COUNT]>>6)&0x00fe);//发送高7位

Matlab(接收端)程序为:

i=1;
k=0; % 最终输出的有效数据个数
while  i<2999
    i = i+1 ;
    if ( bitand(data( i), uint8(1))==1  &&   bitand(data( i+1), uint8(1))==0)
        dat(k) = bitand( bitshift(  data( i) , -1, 'uint16'), 255 ) +data( i+1)*64 ;
        i = i+1 ;
        k=k+1;
    end
end

5.Matlab串口通信

串口发送尽量用 fwrite(Com_obj, data); 而不要用 fprintf(Com_obj, data);  虽然后者有时候也可以运行,但有概率会导致单片机串口卡住,也可能是我的程序有bug。但改用前者就很稳定。

 

PS:本来打算用速率更高的USB进行数据传送的。但GD官方没有给USB函数库的说明, 自己看寄存器和USB协议一时半会儿也调试不出来,就暂时用串口了。

921600的波特率,每次传送3000个数据,可以达到 38FPS的刷新率也基本够用。

 

完。

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值