基本硬件编程问题
Problem with programming a basic hardware
我在 LED 上显示动画。按下按钮时,动画必须停止,然后在再次按下按钮后继续。
有一种处理按钮的方法:
void checkButton(){
GPIO_PinState state;
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
if (state == GPIO_PIN_RESET) {
while(1){
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
if (state == GPIO_PIN_SET){
break;
}
}
//while (state == GPIO_PIN_RESET) {
//state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
//}
}
}
GPIO_PIN_SET 是默认的按钮位置。 GPIO_PIN_RESET是按下按钮时的条件。评论部分是我尝试的而不是 while(1){...}
循环。 checkButton()
方法在主循环中时不时被调用为运行。 STM32上的程序运行s带有扩展模块(这里扩展模块的类型无关紧要)。
事实上,这种方法只是暂时停止了动画,并没有像我希望的那样工作。您能否更正此程序的任何内容以使其正常运行?
Could you correct anything about this program to make it work
properly?
我的猜测是您正试图在设计中添加 'human interaction' 方面。您当前的方法依赖于由 a) 您的应用程序和 b) 人的手指随机定时的单个(按钮位置)样本。这个时间点简直不靠谱,不过改正应该不会太难。
注意 1:'simple' 机械按钮在激活或释放期间会 'bounce'(是的,无论哪种方式)。这意味着软件 'sees'(几微秒内)的值在按下或释放按钮附近的几 (tbd) 毫秒 (?) 内是不可预测的。
注意 2:看待这个问题的另一种方式是,您的状态值存在于两个地方:在物理按钮中和在变量 "GPIO_PinState state;" 中。恕我直言,状态值只能驻留在一个位置。两个位置总是错误的。
然后(如果您相信)解决方案是决定保持一种状态 'record',并消除另一种状态。恕我直言,我想你想保留按钮,这似乎是你的人工输入。明确地说,您想消除变量 "GPIO_PinState state;"
这一行:
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
对开关状态采样一次。
但是,您已经知道这种设计不能依赖于一次读取是否正确。毕竟,您的用户可能刚刚按下或释放按钮,它只是在采样时弹跳。
在我们开始累积样本之前,您应该知道弹跳可能持续的时间远远超过几微秒。我见过一些开关弹跳长达 10 毫秒或更长时间。如果有测试设备,我会把它连接起来,看看你的按钮的特性。如果不行,那好,你可以尝试调整下面示例累加器的控件。
那么,我们如何 'accumulate' 获得足够的样本来确信我们可以知道开关的状态?
考虑多个样本,时间间隔很短(2 个对照?)。我认为你可以简单地积累它们。第一个达到 tbr - 5(或 10 或 100?)样本的计数获胜。因此,旋转采样、延迟并递增两个计数器之一:
stateCount [2] = {0,0}; // state is either set or reset, init both to 0
// vvv-------max samples
for (int i=0; i<100; ++i) // worst case how long does your switch bounce
{
int sample = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15); // capture 1 sample
stateCount[sample] += 1; // increment based on sample
// if 'enough' samples are the same, kick out early
// v ---- how long does your switch bounce
if (stateCount[sample] > 5) break; // 5 or 10 or 100 ms
// to-be-determined --------vvv --- how long does switch bounce
std::this_thread::sleep_for(1ms); // 1, 3, 5 or 11 ms between samples
// C++ provides, but use what is available for your system
// and balanced with the needs of your app
}
仅供参考 - 上面的方案有 3 个调整来处理不同的开关弹跳持续时间......您需要做一些实验。我会从 20 个最大样本开始。我没有 sleep_for 的建议......你没有提供关于你的系统的其他信息。
祝你好运。
已经很久了,但我想我记得电信基础设施设备上的按钮弹跳了 5 到 15 毫秒。
我在 LED 上显示动画。按下按钮时,动画必须停止,然后在再次按下按钮后继续。 有一种处理按钮的方法:
void checkButton(){
GPIO_PinState state;
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
if (state == GPIO_PIN_RESET) {
while(1){
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
if (state == GPIO_PIN_SET){
break;
}
}
//while (state == GPIO_PIN_RESET) {
//state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
//}
}
}
GPIO_PIN_SET 是默认的按钮位置。 GPIO_PIN_RESET是按下按钮时的条件。评论部分是我尝试的而不是 while(1){...}
循环。 checkButton()
方法在主循环中时不时被调用为运行。 STM32上的程序运行s带有扩展模块(这里扩展模块的类型无关紧要)。
事实上,这种方法只是暂时停止了动画,并没有像我希望的那样工作。您能否更正此程序的任何内容以使其正常运行?
Could you correct anything about this program to make it work properly?
我的猜测是您正试图在设计中添加 'human interaction' 方面。您当前的方法依赖于由 a) 您的应用程序和 b) 人的手指随机定时的单个(按钮位置)样本。这个时间点简直不靠谱,不过改正应该不会太难。
注意 1:'simple' 机械按钮在激活或释放期间会 'bounce'(是的,无论哪种方式)。这意味着软件 'sees'(几微秒内)的值在按下或释放按钮附近的几 (tbd) 毫秒 (?) 内是不可预测的。
注意 2:看待这个问题的另一种方式是,您的状态值存在于两个地方:在物理按钮中和在变量 "GPIO_PinState state;" 中。恕我直言,状态值只能驻留在一个位置。两个位置总是错误的。
然后(如果您相信)解决方案是决定保持一种状态 'record',并消除另一种状态。恕我直言,我想你想保留按钮,这似乎是你的人工输入。明确地说,您想消除变量 "GPIO_PinState state;"
这一行:
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
对开关状态采样一次。
但是,您已经知道这种设计不能依赖于一次读取是否正确。毕竟,您的用户可能刚刚按下或释放按钮,它只是在采样时弹跳。
在我们开始累积样本之前,您应该知道弹跳可能持续的时间远远超过几微秒。我见过一些开关弹跳长达 10 毫秒或更长时间。如果有测试设备,我会把它连接起来,看看你的按钮的特性。如果不行,那好,你可以尝试调整下面示例累加器的控件。
那么,我们如何 'accumulate' 获得足够的样本来确信我们可以知道开关的状态?
考虑多个样本,时间间隔很短(2 个对照?)。我认为你可以简单地积累它们。第一个达到 tbr - 5(或 10 或 100?)样本的计数获胜。因此,旋转采样、延迟并递增两个计数器之一:
stateCount [2] = {0,0}; // state is either set or reset, init both to 0
// vvv-------max samples
for (int i=0; i<100; ++i) // worst case how long does your switch bounce
{
int sample = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15); // capture 1 sample
stateCount[sample] += 1; // increment based on sample
// if 'enough' samples are the same, kick out early
// v ---- how long does your switch bounce
if (stateCount[sample] > 5) break; // 5 or 10 or 100 ms
// to-be-determined --------vvv --- how long does switch bounce
std::this_thread::sleep_for(1ms); // 1, 3, 5 or 11 ms between samples
// C++ provides, but use what is available for your system
// and balanced with the needs of your app
}
仅供参考 - 上面的方案有 3 个调整来处理不同的开关弹跳持续时间......您需要做一些实验。我会从 20 个最大样本开始。我没有 sleep_for 的建议......你没有提供关于你的系统的其他信息。
祝你好运。
已经很久了,但我想我记得电信基础设施设备上的按钮弹跳了 5 到 15 毫秒。