搜索
bottom↓
回复: 4

发2个利用AVR的RST复位引脚用作输入接口的做法,无需设置熔丝禁用复位功能

[复制链接]

出330入1880汤圆

发表于 2020-9-6 17:45:15 | 显示全部楼层 |阅读模式
这两天给朋友做一个小东西,打算采用手头一小袋拆机的attiny13,但IO恰好少一个不够用。

众所周知,虽然AVR的RST脚可以通过熔丝设置为IO来使用,但一旦设置成这种模式,就无法再次烧写程序了,因为烧写的时候需要用到RST引脚,
这样相当于是锁了芯片,除非利用高压编程器恢复熔丝,否则无法再次烧写程序,非常麻烦和有风险,虽然不贵,但初学者通常是不敢搞这个操作的。

其实AVR的RST复位引脚在不通过熔丝禁用其复位功能的情况下,也是有办法实现输入功能的。
我简单在论坛搜索了一下,没有看到同样的内容,虽然现在可能用AVR的不多了,但还是决定写下来发个帖子,就当作是记录一下。

本次在不牺牲AVR的RST复位脚的情况下,介绍2种办法通过具备正常复位功能的RST复位引脚,实现信号输入,程序就不贴了,程序上都是常规操作。
注意:这2种方法都可能降低RST复位引脚的稳定性,不应用于恶劣环境和涉及安全的设备。

方法1:
读取AVR的MCUSR寄存器,查看复位原因。
如果是正常上电启动,应该是PORF位Power-on Reset Flag。
如果是RST复位引脚外部复位,则会是EXTRF位External Reset Flag。(注意不同型号这个名称可能不一样,此处以attiny13为例)
通过判断MCUSR寄存器的EXTRF位可以得知RST复位引脚是否被按键一类的东西拉低过。
MCUSR寄存器是可以读写的,读后可以清掉它以便进行下一次判断。
这个方法有一定的缺点,主要是会导致单片机真的复位,可能打乱现有工作,使用这种方法可能导致程序功能的实现有较大变化。
其次,必须注意AVR启动延时完成之前RST复位引脚必须是高电平,否则会出错。
这个方法的好处是很多时候,尤其是开发板,无需任何硬件变更,因为开发板几乎都带有复位按钮。


方法2:
其实在没有禁用RST复位引脚的复位功能时,这个引脚上的ADC功能也是可用的,是能够读到正确的电压的。

对attiny13来说,RST复位引脚上的ADC通道是ADC0,设置ADC以VCC为参考电压,直接读取ADC0通道,即可得到RST复位引脚上的电压信息。
由于RST复位引脚的逻辑电平具备一定的“容限”,小幅度的改变此引脚上的电压不会导致单片机复位,所以在有限范围内作为ADC输入是可用的。
按手册内容来看,绝对安全是范围是0.9*VCC以上,可以有1/10的范围是可用的,ADC值约100,也可以,但电压范围稍小。

考虑到这个引脚有一定的迟滞区间,如果能保证上电时该输入是高,则可以在一定程度上玩火,扩大使用范围。
下图电路在按键按下时会把电压拉到3.3V左右,这个电路在室内经过一周的测试是可以稳定可靠使用的。
在软件上通过ADC值判断按键的状态,我设置了ADC值低于750为低,高于950为高,持续约20ms认为有效,更新状态,运行良好。
理论上,可以用这个方法在RST复位引脚上通过多个电阻实现AD按键,实现多个按键的识别。模拟量输入如果可以限制好范围的话,应该也可以。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2020-9-6 23:04:11 | 显示全部楼层
用ADC的方法不错

出200入2554汤圆

发表于 2020-9-7 00:19:04 | 显示全部楼层
这个折腾可以有

出0入309汤圆

发表于 2020-9-7 00:34:47 | 显示全部楼层
这方法还真不错。
另外attiny自己搭一个高压恢复器也不难。之前调试Attiny85就现搭了一个。


图上电池反了,直接用12V插Arduino的DC口,然后用VIN脚就行。

  1. // AVR High-voltage Serial Fuse Reprogrammer
  2. // Adapted from code and design by Paul Willoughby 03/20/2010
  3. //   http://www.rickety.us/2010/03/arduino-avr-high-voltage-serial-programmer/
  4. //
  5. // Fuse Calc:
  6. //   http://www.engbedded.com/fusecalc/

  7. #define  RST     13    // Output to level shifter for !RESET from transistor
  8. #define  SCI     12    // Target Clock Input
  9. #define  SDO     11    // Target Data Output
  10. #define  SII     10    // Target Instruction Input
  11. #define  SDI      9    // Target Data Input
  12. #define  VCC      8    // Target VCC

  13. #define  HFUSE  0x747C
  14. #define  LFUSE  0x646C
  15. #define  EFUSE  0x666E

  16. // Define ATTiny series signatures
  17. #define  ATTINY13   0x9007  // L: 0x6A, H: 0xFF             8 pin
  18. #define  ATTINY24   0x910B  // L: 0x62, H: 0xDF, E: 0xFF   14 pin
  19. #define  ATTINY25   0x9108  // L: 0x62, H: 0xDF, E: 0xFF    8 pin
  20. #define  ATTINY44   0x9207  // L: 0x62, H: 0xDF, E: 0xFFF  14 pin
  21. #define  ATTINY45   0x9206  // L: 0x62, H: 0xDF, E: 0xFF    8 pin
  22. #define  ATTINY84   0x930C  // L: 0x62, H: 0xDF, E: 0xFFF  14 pin
  23. #define  ATTINY85   0x930B  // L: 0x62, H: 0xDF, E: 0xFF    8 pin

  24. void setup() {
  25.   pinMode(VCC, OUTPUT);
  26.   pinMode(RST, OUTPUT);
  27.   pinMode(SDI, OUTPUT);
  28.   pinMode(SII, OUTPUT);
  29.   pinMode(SCI, OUTPUT);
  30.   pinMode(SDO, OUTPUT);     // Configured as input when in programming mode
  31.   digitalWrite(RST, HIGH);  // Level shifter is inverting, this shuts off 12V
  32.   Serial.begin(19200);
  33. }

  34. void loop() {
  35.    if (Serial.available() > 0) {
  36.     Serial.read();
  37.     pinMode(SDO, OUTPUT);     // Set SDO to output
  38.     digitalWrite(SDI, LOW);
  39.     digitalWrite(SII, LOW);
  40.     digitalWrite(SDO, LOW);
  41.     digitalWrite(RST, HIGH);  // 12v Off
  42.     digitalWrite(VCC, HIGH);  // Vcc On
  43.     delayMicroseconds(20);
  44.     digitalWrite(RST, LOW);   // 12v On
  45.     delayMicroseconds(10);
  46.     pinMode(SDO, INPUT);      // Set SDO to input
  47.     delayMicroseconds(300);
  48.     unsigned int sig = readSignature();
  49.     Serial.print("Signature is: ");
  50.     Serial.println(sig, HEX);
  51.     readFuses();
  52.     if (sig == ATTINY13) {
  53.       writeFuse(LFUSE, 0x6A);
  54.       writeFuse(HFUSE, 0xFF);
  55.     } else if (sig == ATTINY24 || sig == ATTINY44 || sig == ATTINY84 ||
  56.                sig == ATTINY25 || sig == ATTINY45 || sig == ATTINY85) {
  57.       writeFuse(LFUSE, 0x62);
  58.       writeFuse(HFUSE, 0xDF);
  59.       writeFuse(EFUSE, 0xFF);
  60.     }
  61.     readFuses();
  62.     digitalWrite(SCI, LOW);
  63.     digitalWrite(VCC, LOW);    // Vcc Off
  64.     digitalWrite(RST, HIGH);   // 12v Off
  65.   }
  66. }

  67. byte shiftOut (byte val1, byte val2) {
  68.   int inBits = 0;
  69.   //Wait until SDO goes high
  70.   while (!digitalRead(SDO))
  71.     ;
  72.   unsigned int dout = (unsigned int) val1 << 2;
  73.   unsigned int iout = (unsigned int) val2 << 2;
  74.   for (int ii = 10; ii >= 0; ii--)  {
  75.     digitalWrite(SDI, !!(dout & (1 << ii)));
  76.     digitalWrite(SII, !!(iout & (1 << ii)));
  77.     inBits <<= 1;
  78.     inBits |= digitalRead(SDO);
  79.     digitalWrite(SCI, HIGH);
  80.     digitalWrite(SCI, LOW);
  81.   }
  82.   return inBits >> 2;
  83. }

  84. void writeFuse (unsigned int fuse, byte val) {
  85.   shiftOut(0x40, 0x4C);
  86.   shiftOut( val, 0x2C);
  87.   shiftOut(0x00, (byte) (fuse >> 8));
  88.   shiftOut(0x00, (byte) fuse);
  89. }

  90. void readFuses () {
  91.   byte val;
  92.         shiftOut(0x04, 0x4C);  // LFuse
  93.         shiftOut(0x00, 0x68);
  94.   val = shiftOut(0x00, 0x6C);
  95.   Serial.print("LFuse: ");
  96.   Serial.print(val, HEX);
  97.         shiftOut(0x04, 0x4C);  // HFuse
  98.         shiftOut(0x00, 0x7A);
  99.   val = shiftOut(0x00, 0x7E);
  100.   Serial.print(", HFuse: ");
  101.   Serial.print(val, HEX);
  102.         shiftOut(0x04, 0x4C);  // EFuse
  103.         shiftOut(0x00, 0x6A);
  104.   val = shiftOut(0x00, 0x6E);
  105.   Serial.print(", EFuse: ");
  106.   Serial.println(val, HEX);
  107. }

  108. unsigned int readSignature () {
  109.   unsigned int sig = 0;
  110.   byte val;
  111.   for (int ii = 1; ii < 3; ii++) {
  112.           shiftOut(0x08, 0x4C);
  113.           shiftOut(  ii, 0x0C);
  114.           shiftOut(0x00, 0x68);
  115.     val = shiftOut(0x00, 0x6C);
  116.     sig = (sig << 8) + val;
  117.   }
  118.   return sig;
  119. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出330入1880汤圆

 楼主| 发表于 2020-9-7 00:40:55 | 显示全部楼层
iamseer 发表于 2020-9-7 00:34
这方法还真不错。
另外attiny自己搭一个高压恢复器也不难。之前调试Attiny85就现搭了一个。

哈哈,不错,这下搜索而来的人信息就全套了
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-10 14:43

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表