关于匿名上位机好久没有使用了,之前也发过一篇,里面涉及到了一点匿名上位机的使用,最近又重操旧业,再熟悉一下。
—————————————————————————————————————————————————————
Being jealous is a kind of worship
—————————————————————————————————————————————————————
前言
我用的是V4.22版本,软件中有通信协议的介绍,写程序的时候就要严格按照上位机的通讯协议来写
1,我这里用的单片机是stm32f1系列,这里介绍一下数据格式及其范围,等会会用到:
stm32F1系列的CPU为32位,即int位32位
无符号整型 unsigned int:0~4,294,967,295
有符号整型 int:-2,147,483,648~2,147,483,647
无符号字符型 unsigned char:0~255
有符号字符型 char:-128~127
无符号短整型 unsigned short (int):0~65535
有符号短整型 short (int):-32768~32767
无符号整型 unsigned int:0~4,294,967,295
有符号整型 int:-2,147,483,648~2,147,483,647
浮点型 float:-2,147,483,648~2,147,483,647
—————————————————————————————————————————————————————
2,
这里用户可以使用十个自己设置的帧,帧格式如通信协议中所注明的如下图所示,每个帧里面可以有三十个数据,20个数据容器是指在画图的时候有二十条曲线与之对应,即每帧中的三十个数据中的二十个数据可以有二十条曲线用来画图.
还有数据格式要注意,如果发送的数据是u16类型的,short也是16位的都是两个字节,就要单独分高8位、低8位发送,与0xff与后放入u8的数组里面
代码如下
u8 tramsmit_buff[2];
tbuf[0]=(short_MSB>>8)&0XFF;
tbuf[1]=short_LSB&0XFF;
-------------------------------------------------------
最高位 最低位
short_MSB short_LSB
11111111 10101010
那么tbuf[0]=11111111,tbuf[1]=10101010大家可以用单片机debug一下看看是否如此
发送给匿名上位机是高位字节放在数组低位
程序
例子:在单片机上用sin函数生成一个数组,发送给匿名上位机,得到其波形。
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
//串口1发送1个字符
//c:要发送的字符
void usart1_send_char(u8 c)
{
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕
USART_SendData(USART1,c);
}
//传送数据给匿名四轴上位机软件
//fun:功能字.
//data:数据缓存区
//len:data区有效数据个数
void usart1_niming_report(u8 fun,u8*data,u8 len)
{
u8 send_buf[32];
u8 i;
if(len>28)return; //最多28字节数据
send_buf[len+4]=0; //校验数置零
send_buf[0]=0XAA; //帧头
send_buf[1]=0XAA; //功能字
send_buf[2]=fun; //数据长度
send_buf[3]=len; //数据长度
for(i=0;i<len;i++)send_buf[4+i]=data[i]; //复制数据
for(i=0;i<len+4;i++)send_buf[len+4]+=send_buf[i]; //计算校验和
for(i=0;i<len+5;i++)usart1_send_char(send_buf[i]); //发送数据到串口1
}
int main()
{
u16 i;
short array[1];
u8 buff[2];
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
delay_init(); //延时函数初始化
uart_init(115200);
while(1)
{
for(i=0;i<20;i++)
{
array[0]=1000*sin(0.1*3.1415926*i);
buff[0]=(array[0]>>8)&0xFF;
buff[1]=array[0]&0xFF;
usart1_niming_report(0xF1,buff,2);
}
}
}
注意:
1,usart1_niming_report函数中可以举个例子,比如len为1,用的是数据帧1,那么数据帧格式就是
FF FF F1 01 数据字节 校验和
0 1 2 3 4 5
上面关系再代入下面代码理解
send_buf[1+4]=0; //校验数置零 len=1
send_buf[0]=0XAA; //帧头
send_buf[1]=0XAA; //功能字
send_buf[2]=fun; //数据长度 fun=0xF1
send_buf[3]=len; //数据长度 len=1
for(i=0;i<len;i++)send_buf[4+i]=data[i];
2,for循环中的20是sin(0.1✖3.1415926✖i)的周期,这里我刚好取一个完整周期,20个数据,前面要乘以1000是因为提高精度,比如i=1时候,sin(0.13.14159261)=0.309,我用单片机debug了一下,这个值直接为0x0000;乘以1000后就是309了
16进制135就是十进制309
结果
最后在匿名上位机是查看图形
—————————————————————————————————————————————————————
补:定时器的预装载寄存器和影子寄存器
之前发现配置定时器PWM的时候有这两条语句
TIM_ARRPreloadConfig(TIM4, ENABLE)
TIM_0C2PreloadConfig(TIM4, ENABLE)
看下图
图中有阴影的小方框,代表该功能对应的寄存器有影子寄存器,也就是:PSC预分频器、自动重装载寄存器、REP寄存器和4个通道的捕获/比较寄存器。
阴影的寄存器,表示在物理上这个寄存器对应2个寄存器,一个是程序员可以写入或读出的寄存器,称为preload register(预装载寄存器),另一个是程序员看不见的、但在操作中真正起作用的寄存器,称为shadow register(影子寄存器);正如手册上的14.3.1节所说,根据TIMx_CR1寄存器中APRE位的设置,preload register的内容可以随时传送到shadow register,即两者是连通的(permanently),或者在每一次更新事件(UEV)时才把preload register的内容传送到shadow register。
TIM_ARRPreloadConfig(TIM4, DISABLE); 就是上图右边红色时的情况,立刻更新shadow register TIM_ARRPreloadConfig(TIM4, ENABLE);
则是蓝色的情况,通过预装载寄存器,等待下一个跟新时刻再改变shadow register