一、Qt滑块发送端
1、简介
QT中滑动条的控件叫QSlider,继承自QAbstractSlider类。
主要用途是通过滑块的滑动的方式在一定范围内调节某个值。根据调节的后得到的结果去执行一些处理,比如将值写入或者用这个值进行计算,或者进行值传输等等。
通常使用这个控件是希望我们调节滑块到指定位置后,发生一个触发事件,在这个触发事件中,我们获取最后的值,然后进行处理操作。
2、滑块槽函数介绍
其实这6个转换未槽函数的实现就是对应着QAbstractSlider的6个信号量触发函数
//Signals 信号量
void actionTriggered(int action)
void rangeChanged(int min, int max)
void sliderMoved(int value)
void sliderPressed()
void sliderReleased()
void valueChanged(int value)
前面转到槽函数的使用就是依据这6个信号量的触发,执行对应的函数。函数内容自己按需求设计。
void sliderMoved(int value)
这个信号量触发的条件是按下滑块并滑动,就会发出这个信号量,触发对应的槽函数。需要注意的是只要滑块动就会触发,也就是你从1滑动到10,那么1-10中每有一个值是可取的,它都会触发一次。(除非你真就每次只滑动一格,那你没必要用滑动块了)
void sliderPressed()
这个信号量是当滑块按下时触发信号量,执行槽函数,一般情况下也不会用吧,因为按下的时候值是没变的,此时触发不需要进行什么操作。
void sliderReleased()
这个信号量是当滑块释放时,触发信号量可以执行对应的槽函数。这个就比较有用了,可以捕捉到滑动完滑块的那个瞬间,那也是最终的位置,此时的结果正是调节完的结果,执行对应的槽函数去进行值处理。其实这个信号量就可以完成滑块的基本需求了。 但是也还有些局限:通过点击滑动块的方式无法触发信号量。
void valueChanged(int value)
这个信号量是滑块滑动,值发生变化时,就会触发,其实一般使用起来和前面的sliderMoved基本相同,就是少了一个按下滑动块的前提,(不管按不按下滑块)值发生变化时,这个信号量都会触发。同样的从1-10变化,中间每个值都会触发一次。
3、要实现的预期效果
鼠标释放滑块时,将滑块的变化值通过串口发送出去,并判断滑块是向右滑动还是向左滑动。将滑块的当前位置和变化距离显示在窗口。
4、Qt窗口界面设置
5、 .h文件
在.h文件添加滑块槽函数
private slots:
void on_X_distance_sliderReleased();
void on_X_distance_valueChanged(int value);
6、.cpp文件
以Hex格式数据包的形式发送给32,加上帧头帧尾
void MyMainWindow::on_X_distance_sliderReleased()
{
// 获取滑块的当前值
int currentValue = ui->X_distance->value();
int previousSliderValue = 0; //跟踪滑块值
// 判断滑块的滑动方向
if (currentValue > previousSliderValue) {
// 右滑 将距离显示到窗口
ui->X_text_2->setText("+" +QString::number(currentValue-previousSliderValue));
//串口控制步进电机运动
// 转换16进制并通过串口发送
// 创建一个 QByteArray 来包含帧头和数据
QByteArray myString;
myString.append(static_cast<char>(0xFF)); // 添加帧头 0xFF
myString.append(static_cast<char>(0x01)); // 设置电机号
myString.append(static_cast<char>(0x55)); // 设置电机方向 0x55表示正转 0x66表示反转
// 将十六进制字符串转换为 QByteArray 并添加到 myString
myString.append(QByteArray::fromHex(QString::number(currentValue-previousSliderValue, 16).toUtf8()).data());
myString.append("\r\n");// 添加帧尾 \r为0x0D \n为0x0A
serialPort->write(myString);// 通过串口把myString发送出去
} else if (currentValue < previousSliderValue) {
// 左滑
ui->X_text_2->setText(QString::number(currentValue-previousSliderValue));
//串口控制步进电机运动
// 转换16进制并通过串口发送
// 创建一个 QByteArray 来包含帧头和数据
QByteArray myString;
myString.append(static_cast<char>(0xFF)); // 添加帧头 0xFF
myString.append(static_cast<char>(0x01)); // 设置电机号
myString.append(static_cast<char>(0x66)); // 设置电机方向
// 将十六进制字符串转换为 QByteArray 并添加到 myString
myString.append(QByteArray::fromHex(QString::number(previousSliderValue-currentValue, 16).toUtf8()).data());
myString.append("\r\n");// 添加回车和换行符
// 通过串口发送数据
serialPort->write(myString);
}
// 更新上一个值
previousSliderValue = currentValue;
}
void MyMainWindow::on_X_distance_valueChanged(int value)
{
// 更新文本框的值
ui->X_text->setText(QString::number(value));
}
7、效果演示
二、STM32接收端
定义一个数组存放接收到的数据
uint16_t Serial_RxPacket[100]; //定义接收数据包数组,数据包格式"0xFF 0xxx 0x0D 0x0A"
1、串口中断函数
/**
* 函 数:USART1中断函数
* 参 数:无
* 返 回 值:无
* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
* 函数名为预留的指定名称,可以从启动文件复制
* 请确保函数名正确,不能有任何差异,否则中断函数将不能进入
*/
void USART1_IRQHandler(void)
{
static uint8_t RxState = 0; //定义表示当前状态机状态的静态变量
static uint8_t pRxPacket = 0; //定义表示当前接收数据位置的静态变量
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) //判断是否是USART1的接收事件触发的中断
{
uint16_t RxData = USART_ReceiveData(USART1); //读取数据寄存器,存放在接收的数据变量
/*使用状态机的思路,依次处理数据包的不同部分*/
/*当前状态为0,接收数据包包头*/
if (RxState == 0)
{
if (RxData == 0xFF && Serial_RxFlag == 0) //如果数据确实是包头,并且上一个数据包已处理完毕
{
RxState = 1; //置下一个状态
pRxPacket = 0; //数据包的位置归零
}
}
/*当前状态为1,接收数据包数据,同时判断是否接收到了第一个包尾*/
else if (RxState == 1)
{
if (RxData == 0x0D) //如果收到第一个包尾
{
RxState = 2; //置下一个状态
}
else //接收到了正常的数据
{
Serial_RxPacket[pRxPacket] = RxData; //将数据存入数据包数组的指定位置
pRxPacket ++; //数据包的位置自增
}
}
/*当前状态为2,接收数据包第二个包尾*/
else if (RxState == 2)
{
if (RxData == 0x0A) //如果收到第二个包尾
{
RxState = 0; //状态归0
Serial_RxPacket[pRxPacket] = '\0'; //将收到的字符数据包添加一个字符串结束标志
Serial_RxFlag = 1; //接收数据包标志位置1,成功接收一个数据包
}
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除标志位
}
}
2、主函数
while(1)
{
if (Serial_RxFlag == 1) //如果接收到数据包
{
/*将收到的数据包与预设的指令对比,以此决定将要执行的操作*/
if (Serial_RxPacket[0] == 0x01) //
{
if(Serial_RxPacket[1] == 0x55)
{
X_target_distance = Serial_RxPacket[2]; //目标距离=串口接收到的距离
Serial_SendNumber(Serial_RxPacket[2], 3); //将运动距离返回串口
Serial_SendString("\r\n"); //换行
DIR_Forword(); //正转
TIM_Cmd(TIM2, ENABLE); //打开定时器
}
else if(Serial_RxPacket[1] == 0x66)
{
X_target_distance = Serial_RxPacket[2]; //目标距离=串口接收到的距离
Serial_SendNumber(Serial_RxPacket[2], 3); //将运动距离返回串口
Serial_SendString("\r\n"); //换行
DIR_Reversal(); //反转
TIM_Cmd(TIM2, ENABLE); //打开定时器
}
}
Serial_RxFlag = 0;
}
}
三、效果展示
Qt滑块控制步进电机
Qt滑块参考文章:QT——QSlider实现,QT滑动控件的使用-CSDN博客