【问题标题】:Turning a LED on and off with delay on ARM micro-controller在 ARM 微控制器上延迟打开和关闭 LED
【发布时间】:2016-10-20 07:56:52
【问题描述】:

我是嵌入式 C 的新手,并且一直在为它苦苦挣扎。

这个项目的期望输出是:

蓝色 LED 最初应该是亮的。未按下 SW1 时,蓝色 LED 必须保持亮起。当按下 SW1 时,蓝色 LED 应每 100 毫秒打开和关闭一次。 (SW1为负逻辑)。

我编写了这段代码,但它似乎不能正常工作。我在模拟器上试过了,LED 切换,但延迟超过 100 毫秒,就像一秒钟。在真正的板上,我得到随机结果,有时它不会关闭,有时它会变成紫色。为什么这段代码的行为不正常?为什么我会得到随机结果?

示意图

// BranchingFunctionsDelays.c Lab 6
// Runs on LM4F120/TM4C123
// Use simple programming structures in C to
// toggle an LED while a button is pressed and
// turn the LED on when the button is released.  
// This lab will use the hardware already built into the LaunchPad.
// Daniel Valvano, Jonathan Valvano
// January 15, 2016

// built-in connection: PF0 connected to negative logic momentary switch, SW2
// built-in connection: PF1 connected to red LED
// built-in connection: PF2 connected to blue LED
// built-in connection: PF3 connected to green LED
// built-in connection: PF4 connected to negative logic momentary switch, SW1

#include "TExaS.h"

#define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R        (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R      (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_PUR_R        (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R        (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_AMSEL_R      (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R       (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))
#define SYSCTL_RCGC2_GPIOF      0x00000020  // port F Clock Gating Control

// basic functions defined at end of startup.s
void DisableInterrupts(void); // Disable interrupts
void EnableInterrupts(void);  // Enable interrupts
void portF_init(void);
void delay100ms(unsigned long time);


int main(void)
{
        unsigned long volatile delay;
      // activate grader and set system clock to 80 MHz
        TExaS_Init(SW_PIN_PF4, LED_PIN_PF2);  
        portF_init();
        EnableInterrupts();      
        // set PF2
        GPIO_PORTF_DATA_R |= 0x04;
        while(1)
        {
                delay100ms(1);
              // if switch PF4 is pressed and LED is ON (00000101)
            if( GPIO_PORTF_DATA_R == 0x05)
                {
                      // turn LED OFF (clear bit)
                      GPIO_PORTF_DATA_R &= ~0x04;
                }      
                // if switch PF4 is pressed and LED is OFF (00000001)
                else if (GPIO_PORTF_DATA_R == 0x01)
                {
                        // set PF2 - turn LED ON
                      GPIO_PORTF_DATA_R |= 0x04;
                }
                else
                {
                        // set PF2
                        GPIO_PORTF_DATA_R |= 0x04; 
                }
        }
}

void portF_init(void)
{
        volatile unsigned long delay;
        SYSCTL_RCGC2_R |= 0x00000020;     // 1) F clock
        delay = SYSCTL_RCGC2_R;           // delay  
        GPIO_PORTF_AMSEL_R = 0x00;        // 3) disable analog function
        GPIO_PORTF_PCTL_R = 0x00000000;   // 4) GPIO clear bit PCTL  
        GPIO_PORTF_DIR_R = 0x04;          // 5) PF4 input, PF2 output  
        GPIO_PORTF_AFSEL_R = 0x00;        // 6) no alternate function
        GPIO_PORTF_PUR_R = 0x08;          // enable pull-up resistor
        GPIO_PORTF_DEN_R = 0x14;          // 7) enable digital pins PF4 & PF2        
}

void delay100ms(unsigned long time)
{
        unsigned long i;
        while(time > 0)
        {
                i = 1333333;  // this number means 100ms
                while(i > 0)
                {
                        i = i - 1;
                }
                time = time - 1; // decrements every 100 ms
      }
}

【问题讨论】:

  • 作为 delay100ms 函数的开始,将 unsigned long i 更改为 volatile unsigned long itime 也是如此,编译器可能会将您的函数优化为空。
  • 使用硬件计时器进行准确的延迟。您如何计算软件延迟的值?此外,您的延迟功能可能会被 ISR 中断,并且 ISR 执行时间会增加延迟。
  • 你试图一次解决太多问题: 1.首先只做最简单的设置单灯的程序。以这种方式测试所有 LED 及其组合。 2. 然后执行一个程序,当您按下按钮时切换 LED。 3. 然后执行一个程序,无需按下任何按钮即可闪烁 LED。 4. 然后将这三个组合成一个程序。
  • 是的,采取一些小步骤 - 如果你有大量的实现/代码并且它不起作用,你不知道从哪里开始 - 很容易出现多个问题。你应该从基础开始,就像@user694733 说的那样。因此,您可以在可行的东西上构建稍微复杂一些的东西,并在继续更复杂之前调试这些东西
  • 使用调试器。在 while 循环中设置断点。检查按下和未按下 SW1 时 GPIO_PORTF_DATA_R 的值。单步执行代码。正在发生的事情与您的预期/意图不同?

标签: c arm embedded microcontroller


【解决方案1】:

我可以看到您的程序中有一些错误。让我们一一讨论.. 首先定义两个变量,这将使您的代码更具可读性:

#define PF2     0x04
#define PF4     0X10

现在,从 portF_init 开始。更改代码中的这两行: 1. 我们的目标是将PF4位作为输入,PF2作为输出。所以,我们设定的第一件事就是方向。 请注意,当您想修改寄存器的任何位时,请始终使用按位运算符。

GPIO_PORTF_DIR_R ¦= 1 << PF2;

GPIO_PORTF_DIR_R  &= ~(1<< PF4);
  1. 当我们选择任何端口作为输入时,端口状态是未知的。因此,要将其带到已知位置,我们要么上拉,即使其变高,要么将其拉低,默认情况下使其变低。在这里,在我们的例子中,开关是低电平有效,所以我们将默认保持端口状态为上拉。 GPIO_PORTF_PUR_R ¦= 1

不知道有什么用 GPIO_PORTF_DEN_R 你现在可以评论它。保持rest init部分代码不变。

现在,进入执行部分,我们的目标是读取 PF4。现在,您正在尝试读取完整的端口 F 而不仅仅是 PF4 位。因此,无论您在何处尝试阅读 PF4,请将语句更改为:

if (GPIO_PORTF_DATA_R & (1 << PF4) == PF4)  // This statement will only read PF4 bit And tests if PF4 is high

此外,当您尝试打开 LED 时,请使用:

GPIO_PORTF_DATA_R ¦= 1<< PF2;

试试这些建议,让我们知道你的发现。

问候

【讨论】:

  • 很高兴知道这个 Khaled.. 如果我的回答对你有帮助,你能把它标记为答案吗?这也将有助于其他人参考这篇文章。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多