首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >电力系统中几种设备的简单Arduino Uno码联锁

电力系统中几种设备的简单Arduino Uno码联锁
EN

Code Review用户
提问于 2019-12-13 08:03:57
回答 1查看 308关注 0票数 -1

我试图实现一些逻辑功能,以控制一个小型电力系统,包括两个标有T1和T2的变压器、两个发电机(G1和G2)和一个总线绑定(BT)。我不会用不必要的细节压倒你。我需要帮助找出为什么我的Arduino电路不能像预期的那样工作,即使代码编译正确!我花了太多时间在上面,但我还是搞不懂。我会附加电路,然后是注释的Arduino代码。

LEDS应该被一些继电器线圈所取代(一种用来控制电气设备开关的装置)。

以下是Arduino代码:

代码语言:javascript
运行
复制
byte lastReading;
unsigned long lastReadingTimer;
byte UpdatedPortD;
void setup() {
  lastReadingTimer = 0; //Debouncing Timer is 0 ms initially.
  // Initialize ports to I/O directions:
  DDRD = DDRD & B10000011; // Masking to perserve bits 0,1 and 7. (zeros for input)
  DDRB = DDRB | 31;     // Masking to perserve bits 6,7. PortB(8-13 pins) 0001 1111 (one=outputs).
  PORTD &= B10000011;   //Initially all inputs are LOWs.
  lastReading = PORTD & B01111100;
  UpdatedPortD = PORTD & B01111100; // Inputs to PortD, 3-7 pins.
}
//Pins from 3-7 map to switches T1,T2,G1,G2,BT respectively.
//Pins from 8-12 map to devices T1,T2,G1,G2,BT respectively.
void loop() {
  if ((PORTD & B01111100) != lastReading) {
    lastReadingTimer = millis();
  }
  if ( ((millis() - lastReadingTimer) > 50) && (UpdatedPortD != PORTD & B01111100) ) {
    UpdatedPortD = PORTD & B01111100;
  }

  // For T1= G1`.(G2`+BT`) (Simplified LOGIC EQUATION from Truth Table)
  if ( (~UpdatedPortD & (1 << 4))  && ((~UpdatedPortD & (1 << 5)) || (~UpdatedPortD & (1 << 6))) ) {
    PORTB |= 1;
  }
  else if (PORTB & 1) { // if not reset the pin.
    PORTB ^= 1;
  }
  // For T2= G2`.(G1`+BT`)
  if ( (~UpdatedPortD & (1 << 5)) && ((~UpdatedPortD & (1 << 4)) || (~UpdatedPortD & (1 << 6))) ) {
    PORTB |= 1 << 1;
  }
  else if (PORTB & 1 << 1) {
    PORTB ^= 1 << 1;
  }
  // For G1= T1`.(G2`.T2` + BT`)
  if ( (~UpdatedPortD & (1 << 2)) && ((~UpdatedPortD & (1 << 5)) && (~UpdatedPortD & (1 << 3)) || (~UpdatedPortD & (1 << 6))) ) {
    PORTB |= 1 << 2;
  }
  else if (PORTB & 1 << 2) {
    PORTB ^= 1 << 2;
  }
  // For G2= T2`.(G1`.T1` + BT`)
  if ( (~UpdatedPortD & (1 << 3)) && ((~UpdatedPortD & (1 << 4)) && (~UpdatedPortD & (1 << 2)) || (~UpdatedPortD & (1 << 6))) ) {
    PORTB |= 1 << 3;
  }
  else if (PORTB & 1 << 3) {
    PORTB ^= 1 << 3;
  }
  // For BT= G1`.G2`+ T1`.T2`.(G1`+G2`)
  if ( ((~UpdatedPortD & (1 << 4)) && (~UpdatedPortD & (1 << 5))) || (((~UpdatedPortD & (1 << 2)) && (~UpdatedPortD & (1 << 3))) && (~UpdatedPortD & (1 << 4) || ~UpdatedPortD & (1 << 5)))) {
    PORTB |= 1 << 4;
  }
  else if (PORTB & 1 << 4) {
    PORTB ^= 1 << 4;
  }
  lastReading = PORTD & B01111100;
}

非常感谢!

EN

回答 1

Code Review用户

回答已采纳

发布于 2019-12-13 11:33:15

  • 对于嵌入式系统,不要使用C的本地整数类型,也不要使用像byte这样奇怪的自定义类型。始终使用stdint.h中的类型。
  • 避免在文件范围内声明变量。如果必须这样做,因为它们是在同一个文件中的多个函数之间共享的,那么将它们声明为static以缩小范围。
  • 不要使用二进制常量0b,因为它们是非标准的和不可移植的.此外,它们很难读懂。假定程序员能够读懂十六进制。
  • 同样,也不要用像31这样的十进制数字来掩盖,这就更让人困惑了。0x1F要清楚得多。
  • 根本不用“魔法数字”。而不是像DDRD = DDRD & B10000011;这样的代码,您应该有类似于DDRD = DDRD0 | DDRD1 | DDRD7的东西。这现在是自记录代码,因此注释“掩蔽0,1和7位”不再是必要的。
  • 硬件外围寄存器不应视为正常变量!当访问硬件寄存器时,避免不必要地多次访问它们,因为这可能导致意外的评估错误顺序或额外的不必要的读取访问。或者更糟的是,在编写最终值之前,伪写会非常快地切换端口--这样的代码会产生EMI和硬件故障。void loop()应该重写为: uint8_t portb = PORTB;uint8_t portd = PORTD;/* all if语句和算术使用上述2个RAM变量*/ uint8_t= portb;//写入端口一次,当完成时
  • 大多数运营商在一条线路上没有奖励,恰恰相反。像if ( ((~UpdatedPortD & (1 << 4)) && (~UpdatedPortD & (1 << 5))) || (((~UpdatedPortD & (1 << 2)) && (~UpdatedPortD & (1 << 3))) && (~UpdatedPortD & (1 << 4) || ~UpdatedPortD & (1 << 5))))这样的表达式需要在几行中分成几个表达式。重要的是要认识到这样做不会导致更慢的代码。此外,您也可以使用有意义的变量名,而不是让程序使用“神奇端口号”。只是一个带有随机名称的例子,因为我不知道您的实际按钮在做什么: bool button_up = ~UpdatedPortD & (1u<<2);bool button_down = ~UpdatedPortD & (1u<<3);bool button_left = ~UpdatedPortD & (1u<<4);bool button_right = ~UpdatedPortD & (1u<<5);if(button_up && button_left) { /* do buttons */ }
  • 您的代码在隐式整数类型提升中有常见的嵌入式系统问题,它总是等待爆炸的定时炸弹。例如,~UpdatedPortD为您提供了一个16位签名的int,其值为0xFF** (负值),这不是您想要的。1 << 4;在16位签名的int上执行位移位。诸若此类。不要对有符号类型使用按位操作!要解决这个问题,总是将提升的表达式转换回预期的类型,并在重要的地方始终使用u后缀整数常量。1 << 4应该是1u << 4。总的来说,传统的8位MCU很难编程,隐性促销是其中一个原因。我强烈建议初学者使用32位手臂代替,因为他们是更直截了当。
  • 50 is是一个很长的去弹时间,以至于人类可能开始注意到延迟(我们可能开始注意到大约100 is及以后的延迟)。大多数开关不需要那么长,10毫秒足够大多数按钮,如触觉开关等。如果有疑问,把按钮连接到示波器,给它5V,并观察反弹。
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/233961

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档