STC管脚上电如何输出低电平

最近在做一个项目,其中电路板部分功能原理是,STC MCU直接连接ULN2003,再驱动ULN2003控制继电器。本来一切正常的,后面在细调的时候发现有一个问题,就是在电路板上电瞬间或MCU复位瞬间,所有的继电器都会闭合一下,这个误动作是很有问题的,必须避免。该现象的原因我很清楚,即STC MCU上电默认所有管脚都会输出高电平,而我在初始化程序中,将继电器对应的控制IO初始化为低电平,但这之间还是存在一小段时间,管脚输出的是高电平。

    通过参看STC器件的使用手册,上面提供了一种方法可以使管脚上电输出低电平,在此一并说下:即在需要上电保持低电平的管脚上,加一个较小阻值的下拉电阻(如1K/2K/3K)。因为STC MCU上电时,所有的管脚的属性都会默认恢复为普通GPIO,该模式下的弱上拉电阻不足以在接了较小的下拉电阻时,将管脚电平拉高,从而避免了上电时输出高电平。而在之后的程序初始化中,再设置对应管脚电平,并设置管脚模式为推挽输出,推挽输出模式下的电流 可以即便在较小的下拉电阻时,仍将管脚电平拉至高电平。从原理上来说,这样是没错的,但唯一的问题是 这意味着要重新制板。所以我实验了很多种其它方法,以期在不改动现有硬件电路的前提下,实现MCU的管脚上电输出低电平。当然,最后我成功了 ;)   在介绍具体的做法之前先介绍两个事实:

    第一、STC MCU或者说51单片机,在上电时,都会先执行一个名为STARTUP.A51的文件里的汇编程序的,在该段汇编程序中,MCU会进行最初的初始化,包括一些堆栈参数设置,工作区选定,数据初始化等。而我们平时所写的程序,是在该段汇编程序执行完了之后,才会跳过来的,所以从系统上电到执行初始化应用程序之间是有一定的时间间隔的。

    第二,STC MCU的管脚有四种模式:1,准双向口,传统8051的I/O模式,灌电流可达20mA,拉电流270uA,即可以接受较大的输入电流,和输出较小的电流;2、推挽输出,具有较大的拉电流,可达20mA,和准双向口的区别就是具有较大输出电流;3、高阻输入,该模式下,管脚既不能输出电流,也不能接受输入电流;4,开漏模式,和准双向口的区别就是不能输出拉电流,即对外不能输出高电平。而我解决 MCU上电输出高电平,就需要设置管脚模式为高阻或开漏。


STC MCU管脚模式以及设置方法

  最后,具体的做法思路是这样的:在STARTUP.A51中,使用汇编语言 对需要上电输出低电平的管脚,设置其管脚属性为高阻或开漏,然后在应用程序中,先将控制管脚的电平初始化后,再重新设置这些控制管脚的模式。这样,在MCU上电后,运行到汇编程序中的管脚属性初始化这点时间就很短,并且STC MCU在下载程序时,ISP软件设置 不需要使用额外复位延时。最后上图上程序上真相:


ISP下载时的设置,不勾选上电复位使用较长延时


另还要注意的第一点是:该段管脚属性初始化程序应该加载STARTUP1段中,并且在该汇编程序文件的开头部分声明这些寄存器:

eg.

P2M1 DATA   095H
P2M0 DATA   096H
P4M1 DATA   0b3H
P4M0 DATA   0b4H

第二点是,在使用Keil建立工程时,应该选择不使用默认的STARTUP.A51,并从Keil的安装目录下,找到这个STARTUP.A51(这个相信不难了),把它放到自己的应用程序目录下,然后添加到Keil中,再进行此项修改,如下图所示:



最后,没改动任何硬件线路,即实现了MCU上电或复位后,既定管脚输出低电平,防止控制的后级误动作。

贴出startup.a51下载地址,仅供参考,慎用。

http://download.csdn.net/detail/firestarway/9349829

  • 7
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
下位机代码: ```c #include <reg52.h> sbit P00 = P0^0; // 定义P00管脚 sbit P10 = P1^0; // 定义P10管脚 sbit P20 = P2^0; // 定义P20管脚 void main() { unsigned char ch; // 用于存储接收到的字符 TMOD = 0x20; // 定时器1工作模式2 TH1 = 0xfd; // 波特率9600 TL1 = 0xfd; TR1 = 1; // 启动定时器1 SCON = 0x50; // 串口工作在模式1 ES = 1; // 开启串口中断 EA = 1; // 开启总中断 while(1); // 无限循环等待接收到数据 } void UART_ISR() interrupt 4 // 串口中断服务函数 { unsigned char ch; if(RI) { RI = 0; // 清除接收中断标志位 ch = SBUF; // 读取接收到的数据 switch(ch) { case 0x00: P00 = 0; break; // 接收到0x00时,P00输出低电平 case 0x01: P00 = 1; break; // 接收到0x01时,P00输出高电平 case 0x80: P10 = 0; break; // 接收到0x80时,P10输出低电平 case 0x81: P10 = 1; break; // 接收到0x81时,P10输出高电平 case 0x150: P20 = 0; break; // 接收到0x150时,P20输出低电平 case 0x151: P20 = 1; break; // 接收到0x151时,P20输出高电平 default: break; } } } ``` 上位机代码: ```python import serial import time ser = serial.Serial('COM3', 9600, timeout=0.5) # 打开串口 while True: cmd = input("请输入指令:") # 获取用户输入的指令 if cmd == 'exit': # 输入exit退出程序 break ser.write(bytes.fromhex(cmd)) # 将指令转换为字节串并发送给下位机 time.sleep(0.5) # 延时0.5秒,等待下位机响应 if ser.in_waiting: # 如果串口缓冲区中有数据 res = ser.read(ser.in_waiting).decode() # 读取缓冲区中的数据并解码为字符串 print(res) # 输出响应结果 ser.close() # 关闭串口 ``` 注意事项: 1. 下位机代码中使用了串口中断服务函数,需要开启总中断(EA=1)才能正常工作。 2. 上位机代码中使用了bytes.fromhex()将字符串转换为字节串,确保指令正确发送。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值