单片机

介绍

一种无OS的MCU实用软件框架,包括任务轮询管理,命令管理器、低功耗管理、环形缓冲区等实用模块。系统中广泛利用自定义段技术减少各个模块间的耦合关系,大大提供程序的可维护性。

主要功能

  • 支持模块自动化管理,并提供不同优先等级初始化声明接口。
  • 支持任务轮询管理,通过简单的宏声明即可实现,不需要复杂的声明调用。
  • 支持低功耗管理,休眠与唤醒通知。
  • 支持命令行解析,命令注册与执行。
  • blink设备支持,统一管理LED、震动马达、蜂鸣器

使用说明

完整的代码可以参考工程文件,系统开发平台如下:

MCU:STM32F401RET6

IDE:IAR 7.4或者Keil MDK 4.72A

任务初始化及任务轮询管理(module)

使用此模块前需要系统提供滴答定时器,用于驱动任务轮询作业。(参考platform.c)

使用说明//定时器中断(提供系统滴答)
void SysTick_Handler(void)
{
systick_increase(SYS_TICK_INTERVAL); //增加系统节拍
}

注册初始化入口及任务(参考自key_task.c)

使用说明static void key_init(void)
{
/*do something*/
}

static void key_scan(void)
{
/*do something*/
}

module_init("key", key_init); //注册按键初始化接口
driver_register("key", key_scan, 20); //注册按键任务(20ms轮询1次)

命令管理器(cli)

适用于在线调试、参数配置等(参考使用cli_task.c),用户可以通过串口输出命令行控制设备行为、查询设备状态等功能。

命令格式

cli支持的命令行格式如下:

<cmd name> < param1> < param2> < paramn> < \r\n > <cmd name> ,< param1>, < param2>, < paramn>, < \r\n >

每行命令包含一个命令名称+命令参数(可选),命令名称及参数可以通过空格或者','进行分隔。

系统默认命令

cli系统自带了2条默认命令,分别是"?"与"help"命令,输入他们可以列出当前系统包含的命令列表,如下所示:

?         - alias for 'help'
help      - list all command.
pm        - Low power control command
reset     - reset system
sysinfo   - show system infomation.

适配命令管理器

完整的例子可以参考cli_task.c.

static cli_obj_t cli;                               /*命令管理器对象 */

/* 
 * @brief       命令行任务初始化
 * @return      none
 */ 
static void cli_task_init(void)
{
    cli_port_t p = {tty.write, tty.read};           /*读写接口 */

    cli_init(&cli, &p);                             /*初始化命令行对象 */

    cli_enable(&cli);

    cli_exec_cmd(&cli,"sysinfo");                   /*显示系统信息*/
}

/* 
 * @brief       命令行任务处理
 * @return      none
 */ 
static void cli_task_process(void)
{
    cli_process(&cli);
}

module_init("cli", cli_task_init);                  
task_register("cli", cli_task_process, 10);          /*注册命令行任务*/

命令注册

以复位命令为例(参考cmd_devinfo.c):

#include "cli.h"
//...
/* 
 * @brief       复位命令
 */ 
int do_cmd_reset(struct cli_obj *o, int argc, char *argv[])
{
    NVIC_SystemReset();
    return 0;
}cmd_register("reset",do_cmd_reset, "reset system");

低功耗管理器(pm)

控制间歇运行,降低系统功耗。其基本的工作原理是通过轮询系统中各个模块是否可以允许系统进入低功耗。实际上这是一种判决机制,所有模块都具有有票否决权,即只要有一个模块不允许休眠,那么系统就不会进入休眠状态。pm模块在休眠前会统计出各个模块会返回最小允许休眠时长,并以最小休眠时长为单位进行休眠。

如何适配

使用前需要通过pm_init进行初始化适配,并提供当前系统允许的最大休眠时间,进入休眠的函数接口,基本的接口定义如下:

/*低功耗适配器 ---------------------------------------------------------*/
typedef struct {
    /**
     * @brief    系统最大休眠时长(ms)
     */  
    unsigned int max_sleep_time;
    /**
     * @brief     进入休眠状态
     * @param[in] time - 期待休眠时长(ms)
     * @retval    实际休眠时长
     * @note      休眠之后需要考虑两件事情,1个是需要定时起来给喂看门狗,否则会在休眠
     *            期间发送重启.另外一件事情是需要补偿休眠时间给系统滴答时钟,否则会
     *            造成时间不准。
     */     
    unsigned int (*goto_sleep)(unsigned int time);
}pm_adapter_t;
void pm_init(const pm_adapter_t *adt);

void pm_enable(void);

void pm_disable(void);

void pm_process(void);

完成的使用例子可以参考platform-lowpower.c,默认情况下是禁用低功耗功能的,读者可以去除工程中原来不带低功耗版本的platform.c,并加入platform-lowpower.c文件进行编译即可使用。

注册低功耗设备

以按键扫描为例,正常情况下,如果按键没有按下,那么系统休眠可以进入休眠状态,对按键功能是没有影响的。如果按键按下时,那么系统需要定时唤醒并轮询按键任务。

所以在一个低功耗系统下,为了不影响按键实时性需要处理好两个事情:

1)系统休眠状态下,如果有按键按下,那系统系统应立即唤醒,以便处理接下来的扫描工作。

2)如果按键按下时,系统可以进入休眠,但需要定时唤醒起来轮询按键任务。

对于第一种情况,将按键配置为边沿中断唤醒即可,以STM32F4为例(参考key_task.c),它支持外部中断唤醒功能。

/* 
 * @brief       按键 io初始化
 *              PC0 -> key;
 * @return      none
 */ 
static void key_io_init(void)
{
    /* Enable GPIOA clock */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    gpio_conf(GPIOC, GPIO_Mode_IN, GPIO_PuPd_UP, GPIO_Pin_0);

    //低功耗模式下,为了能够检测到按键,配置为中断唤醒
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource0);
    exti_conf(EXTI_Line0, EXTI_Trigger_Falling, ENABLE);
    nvic_conf(EXTI0_IRQn, 0x0F, 0x0F);

    key_create(&key, readkey, key_event);            /*创建按键*/
}

对于第二种情况,可以通过pm_dev_register来处理,当系统请求休眠时,如果此时按键按下,则返回下次唤醒时间即可,如下面的例子所示。

//参考key_task.c
#include "pm.h"                                     
/*
 * @brief	   休眠通知
 */
static unsigned int  key_sleep_notify(void)
{
    return key_busy(&key) || readkey() ? 20 : 0;    /* 非空闲时20ms要唤醒1次*/
} pm_dev_register("key", NULL, key_sleep_notify, NULL);

blink模块

具有闪烁特性(led, motor, buzzer)的设备(led, motor, buzzer)管理

使用步骤:

  • 需要系统提供滴答时钟,blick.c中是通过get_tick()接口获取,依赖module模块
  • 需要在任务中定时进行轮询

或者通过"module"模块的任务注册来实现

task_register("blink", blink_dev_process, 50);  //50ms轮询1次

LED驱动

blink_dev_t led;                             //定义led设备

/*
 *@brief     红色LED控制(GPIOA.8)
 *@param[in] on - 亮灭控制
 */
static void led_ctrl(int on)
{
    if (on)
        GPIOA->ODR |= (1 << 8);
    else 
        GPIOA->ODR &= ~(1 << 8);
}

/*
 *@brief     led初始化程序
 */
void led_init(void)
{
    led_io_init(void);                  //led io初始化
    blink_dev_create(&led, led_ctrl);   //创建led设备

    blink_dev_ctrl(&led, 50, 100, 0);   //快闪(50ms亮, 100ms灭)
}

按键管理模块

类似blink模块,使用之前有两个注意事项:

  • 需要系统提供滴答时钟,key.c中是通过get_tick()接口获取,依赖module模块

  • 需要在任务中定时进行轮询

key_t key;                             //定义按键管理器

/*
 *@brief     按键事件
 *@param[in] type     - 按键类型(KEY_PRESS, KEY_LONG_DOWN, KEY_LONG_UP)  
 *@param[in] duration - 长按持续时间
 */
void key_event(int type, unsigned int duration)
{
	if (type == KEY_PRESS) {                //短按

	} else if (type == KEY_LONG_DOWN) {     //长按

	}
} 

//读取键值(假设按键输出口为STM32 MCU PA8)
int read_key(void)
{
	return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8) == Bit_RESET;
}

/*
 *@brief     按键初始化
 */
void key_init(void)
{
    //打开GPIO 时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	//配置成输入模式
    gpio_conf(GPIOA, GPIO_Mode_IN, GPIO_PuPd_NOPULL, GPIO_Pin_8); 
    //创建1个按键
    key_create(&key, read_key, key_event);  
}

开源地址:

https://gitee.com/moluo-tech/CodeBrick

来源 | 魔罗技术
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 63

我以前开发过多款带有触摸按键功能的消费类电子产品,用的是现成的“触摸IC”。但后来才知道,有些芯片就是用低功耗单片机实现的。

下面,结合STM8和STM32来简单描述一下相关内容。

STM8触摸原理及开发库

先简述一下在STM8S中应用Resistor-Capacitor电阻电容(RC)采集原理。

“单片机的GPIO,如何实现触摸按键的功能?"

硬件原理,可以参考官网:

“单片机的GPIO,如何实现触摸按键的功能?"

“单片机的GPIO,如何实现触摸按键的功能?"

使用MCU的资源:

“单片机的GPIO,如何实现触摸按键的功能?"

官网提供STM8库相关开发资料:
https://www.st.com/en/embedded-software/stm8s-touch-lib.html

STM32触摸感应控制器

相比STM8而言,STM32的触摸按键功能就更高级。

在STM32中,部分MCU(F0、 F3、 L1)具有Touch sensing controller触摸感应控制器,简称TSC。

这里可以参看ST社区的一份关于文档《STM32F0—触摸按键》:
http://www.stmcu.org.cn/document/detail/index/id-213949

或者查看MCU对应的《参考手册》,可以知道触摸控制器:电荷转移的过程以及其原理。

“单片机的GPIO,如何实现触摸按键的功能?"
  • 利用电容储存电荷的特性;

  • 电极上的待测电容Cx向采样电容Cs充电;

  • 电荷转移过程中个模拟开关是硬件做在GPIO里的;

  • 重复电荷转移的过程,直到采样电容Cs上的电压达到它说连GPIO的VIH门限值;

  • 过程重复的次数就反映了待测电极上电容的大小;

  • 电极被触摸时,重复次数N减小。

更多参考资料:

关于Touch触摸的标准外设库:

https://www.st.com/en/embedded-software/stm32-standard-peripheral-library-expansion.html?querycriteria=productId=LN1734

“单片机的GPIO,如何实现触摸按键的功能?"

官方提供的一套关于Touch文档,值得参看:
https://www.st.com/content/ccc/resource/technical/document/user_manual/5d/e8/16/b7/a5/f5/47/bf/DM00075710.pdf/files/DM00075710.pdf/jcr:content/translations/en.DM00075710.pdf

作者:strongerHuang
来源:嵌入式专栏
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 277

在平常的项目开发过程中,会遇到各种各样的问题。下面分享一篇文章,是常见问题的解决思路和办法。

一、问题复现

稳定复现问题才能正确的对问题进行定位、解决以及验证。一般来说,越容易复现的问题越容易解决。

1.1 模拟复现条件

有的问题存在于特定的条件下,只需要模拟出现问题的条件即可复现。对于依赖外部输入的条件,如果条件比较复杂难以模拟可以考虑程序里预设直接进入对应状态。

1.2 提高相关任务执行频率

例如某个任务长时间运行才出现异常则可以提高该任务的执行频率。

1.3 增大测试样本量

程序长时间运行后出现异常,问题难以复现,可以搭建测试环境多套设备同时进行测试。

二、问题定位

缩小排查范围,确认引入问题的任务、函数、语句。

2.1 打印LOG

根据问题的现象,在抱有疑问的代码处增加LOG输出,以此来追踪程序执行流程以及关键变量的值,观察是否与预期相符。

2.2 在线调试

在线调试可以起到和打印LOG类似的作用,另外此方法特别适合排查程序崩溃类的BUG,当程序陷入异常中断(HardFault,看门狗中断等)的时候可以直接STOP查看call stack以及内核寄存器的值,快速定位问题点。

2.3 版本回退

使用版本管理工具时可以通过不断回退版本并测试验证来定位首次引入该问题的版本,之后可以围绕该版本增改的代码进行排查。

2.4 二分注释

二分注释即以类似二分查找法的方式注释掉部分代码,以此判断问题是否由注释掉的这部分代码引起。

具体方法为将与问题不相干的部分代码注释掉一半,看问题是否解决,未解决则注释另一半,如果解决则继续将注释范围缩小一半,以此类推逐渐缩小问题的范围。

2.5 保存内核寄存器快照

Cortex M内核陷入异常中断时会将几个内核寄存器的值压入栈中,如下图:

“30个单片机常见问题及解决办法"

我们可以在陷入异常中断时将栈上的内核寄存器值写入RAM的一段复位后保留默认值的区域内,执行复位操作后再从RAM将该信息读出并分析,通过PC、LR确认当时执行的函数,通过R0-R3分析当时处理的变量是否异常,通过SP分析是否可能出现栈溢出等。

三、问题分析处理

结合问题现象以及定位的问题代码位置分析造成问题的原因。

3.1 程序继续运行

3.1.1 数值异常
3.1.1.1 软件问题

数组越界

写数组时下标超出数组长度,导致对应地址内容被修改。如下:

“30个单片机常见问题及解决办法"

此类问题通常需要结合map文件进行分析,通过map文件观察被篡改变量地址附近的数组,查看对该数组的写入操作是否存在如上图所示不安全的代码,将其修改为安全的代码。

栈溢出

“30个单片机常见问题及解决办法"

如上图,此类问题也需要结合map文件进行分析。假设栈从高地址往低地址增长,如果发生栈溢出,则g_val的值会被栈上的值覆盖。

出现栈溢出时要分析栈的最大使用情况,函数调用层数过多,中断服务函数内进行函数调用,函数内部申明了较大的临时变量等都有可能导致栈溢出。

解决此类问题有以下方法:

在设计阶段应该合理分配内存资源,为栈设置合适的大小;

将函数内较大的临时变量加”static”关键字转化为静态变量,或者使用malloc()动态分配,将其放到堆上;

改变函数调用方式,降低调用层数。

判断语句条件写错

“30个单片机常见问题及解决办法"

判断语句的条件容易把相等运算符“==”写成赋值运算符“=”导致被判断的变量值被更改,该类错误编译期不会报错且总是返回真。

建议将要判断的变量写到运算符的右边,这样错写为赋值运算符时会在编译期报错。还可以使用一些静态代码检查工具来发现此类问题。

同步问题

例如操作队列时,出队操作执行的过程中发生中断(任务切换),并且在中断(切换后的任务)中执行入队操作则可能破坏队列结构,对于这类情况应该操作时关中断(使用互斥锁同步)。

优化问题

“30个单片机常见问题及解决办法"

如上图程序,本意是等待irq中断之后不再执行foo()函数,但被编译器优化之后,实际运行过程中flg可能被装入寄存器并且每次都判断寄存器内的值而不重新从ram里读取flg的值,导致即使irq中断发生foo()也一直运行,此处需要在flg的申明前加“volatile”关键字,强制每次都从ram里获取flg的值。

3.1.1.2 硬件问题

芯片BUG

芯片本身存在BUG,在某些特定情况下给单片机返回一个错误的值,需要程序对读回的值进行判断,过滤异常值。

通信时序错误

“30个单片机常见问题及解决办法"

例如电源管理芯片Isl78600,假设现在两片级联,当同时读取两片的电压采样数据时,高端芯片会以固定周期通过菊花链将数据传送到低端芯片,而低端芯片上只有一个缓存区.

如果单片机不在规定时间内将低端芯片上的数据读走那么新的数据到来时将会覆盖当前数据,导致数据丢失。此类问题需要仔细分析芯片的数据手册,严格满足芯片通信的时序要求。

3.1.2 动作异常

3.1.2.1 软件问题

设计问题

设计中存在错误或者疏漏,需要重新评审设计文档。

实现与设计不符

代码的实现与设计文档不相符需要增加单元测试覆盖所有条件分支,进行代码交叉review。

状态变量异常

例如记录状态机当前状态的变量被篡改,分析该类问题的方法同前文数值异常部分。

3.1.2.2 硬件问题

硬件失效

目标IC失效,接收控制指令后不动作,需要排查硬件。

通信异常

与目标IC通信错误,无法正确执行控制命令,需要使用示波器或逻辑分析仪去观察通信时序,分析是否发出的信号不对或者受到外部干扰。

3.2 程序崩溃

3.2.1 停止运行

3.2.1.1 软件问题

HardFault

以下情况会造成HardFault:

在外设时钟门未使能的情况下操作该外设的寄存器;

跳转函数地址越界,通常发生在函数指针被篡改,排查方法同数值异常;

解引用指针时出现对齐问题:

以小端序为例,如果我们声明了一个强制对齐的结构体如下:

“30个单片机常见问题及解决办法"

“30个单片机常见问题及解决办法"

此时a.val1的地址为0x00000001,如果以uint16_t类型去解引用此地址则会因为对齐问题进入HardFault,如果一定要用指针方式操作该变量则应当使用memcpy()。

中断服务函数中未清除中断标志

中断服务函数退出前不正确清除中断标志,当程序执行从中断服务函数内退出后又会立刻进入中断服务函数,表现出程序的“假死”现象。

NMI中断

调试时曾遇到SPI的MISO引脚复用NMI功能,当通过SPI连接的外设损坏时MISO被拉高,导致单片机复位后在把NMI引脚配置成SPI功能之前就直接进入NMI中断,程序挂死在NMI中断中。这种情况可以在NMI的中断服务函数内禁用NMI功能来使其退出NMI中断。

3.2.1.2 硬件问题

1)晶振未起振

2)供电电压不足

3)复位引脚拉低

3.2 .2 复位

3.2.2.1 软件问题

看门狗复位

除了喂狗超时导致的复位以外,还要注意看门狗配置的特殊要求,以Freescale KEA单片机为例,该单片机看门狗在配置时需要执行解锁序列(向其寄存器连续写入两个不同的值),该解锁序列必须在16个总线时钟内完成,超时则会引起看门狗复位。此类问题只能熟读单片机数据手册,注意类似的细节问题。

3.2.2.2 硬件问题

1)供电电压不稳

2)电源带载能力不足

四、回归测试

问题解决后需要进行回归测试,一方面确认问题是否不再复现,另一方面要确认修改不会引入其他问题。

五、经验总结

总结本次问题产生的原因及解决问题的方法,思考类似问题今后如何防范,对相同平台产品是否值得借鉴,做到举一反三,从失败中吸取经验。

作者:jozo_chen
原文地址:
www.cnblogs.com/jozochen/p/8541714.html
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 305

在传感器使用中,我们常常需要对传感器数据进行各种整理,让应用获得更好的效果,以下介绍几种常用的简单处理方法:

加权平滑:平滑和均衡传感器数据,减小偶然数据突变的影响。
抽取突变:去除静态和缓慢变化的数据背景,强调瞬间变化。
简单移动平均线:保留数据流最近的K个数据,取平均值。

下面,具体介绍一下这3种处理方法。

1、加权平滑

使用算法如下:

(新值) = (旧值)*(1 - a) + X * a其中a为设置的权值,X为最新数据,程序实现如下:

float ALPHA = 0.1f;
public void onSensorChanged(SensorEvent event){
x = event.values[0];
y = event.values[1];
z = event.values[2];
mLowPassX = lowPass(x,mLowPassX);
mLowPassY = lowPass(x,mLowPassY);
mLowPassZ = lowPass(x,mLowPassZ);
}
private float lowPass(float current,float last){
return last * (1.0f - ALPHA) + current * ALPHA;
}

2、抽取突变

此算法采用上面加权平滑的逆算法,实现代码如下:

public void onSensorChanged(SensorEvent event){
final float ALPHA = 0.8;gravity[0] = ALPHA * gravity[0] + (1-ALPHA) * event.values[0];
gravity[1] = ALPHA * gravity[1] + (1-ALPHA) * event.values[1];
gravity[2] = ALPHA * gravity[2] + (1-ALPHA) * event.values[2];filteredValues[0] = event.values[0] - gravity[0];
filteredValues[1] = event.values[1] - gravity[1];
filteredValues[2] = event.values[2] - gravity[2];
}

3、简单移动平均线

这个算法,保留传感器数据流中最近的K个数据,返回它们的平均值。k表示平均“窗口”的大小,实现代码如下:

public class MovingAverage{
private float circularBuffer[]; //保存传感器最近的K个数据
private float avg; //返回到传感器平均值
private float sum; //数值中传感器数据的和
private float circularIndex; //传感器数据数组节点位置
private int count;public MovingAverage(int k){
circularBuffer = new float[k];
count= 0;
circularIndex = 0;
avg = 0;
sum = 0;
}
public float getValue(){
return arg;
}
public long getCount(){
return count;
}
private void primeBuffer(float val){
for(int i=0;i<circularbuffer.length;++i){
 circularBuffer[i] = val;
sum += val;
}
}
private int nextIndex(int curIndex){
if(curIndex + 1 >= circularBuffer.length){
return 0;
}
return curIndex + 1;
}
public void pushValue(float x){
if(0 == count++){
primeBuffer(x);
}
float lastValue = circularBuffer[circularIndex];
circularBuffer[circularIndex] = x; //更新窗口中传感器数据
sum -= lastValue; //更新窗口中传感器数据和
sum += x;
avg = sum / circularBuffer.length; //计算得传感器平均值
circularIndex = nextIndex(circularIndex);
}
}

来源:STM32嵌入式开发
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:
cathy@eetrend.com)。

围观 22

1、8bit MCU 通用I/O 结构图

端口模块如下图(79系列图):

“中颖8bit

2、相关设置寄存器及注意事项:

端口控制寄存器

“中颖8bit

“中颖8bit

PxCR寄存器控制I/O输入输出状态设置。

当寄存器设置成输入模式时,Px寄存器读取的是端口电平状态。

当寄存器设置成输出模式时,Px寄存器读取的是数据寄存器的值。

如有未使用到的I/O,需要设置输出固定电平以免I/O浮动电平带来的漏电流。

端口上拉电阻控制寄存器

“中颖8bit

“中颖8bit

端口数据寄存器

“中颖8bit

“中颖8bit

79系列单片机 Px 寄存器都在位寻址区(例如:80H,88H等),都可以进行位寻址操作。

在初始化设施PxCR(输出状态)前,请优先设置Px寄存器,避免WDT,,OVL等复位带来的端口电平变化。

当PxCR寄存器设置成输入状态时,操作读取对应Px,是读取对应引脚电平状态。

当PxCR寄存器设置成输出状态时,根据指令来分别对应 读取的是寄存器还是引脚电平。

端口寄存器读-改-写指令举例:

ANL P0, #立即数 ; P0->立即数&(与)P0->P0

ORL P0, A ; P0->A|(或)P0->P0

INC P0 ; P0->P0+1->P0

CPL P0.0 ; P0.0->P0.0~(取反)->P0.0

引脚电平读取指令举例:

MOV A,P0 ; P0->A

MOV R0, P0 ; P0->R0

不管端口是否共享为其它功能,对端口写操作都是针对端口数据寄存器。

当第二功能有冲突时,按照端口共享表格中的优先级来决定输出功能。

通常I/O的优先级是低于其他功能的。

以下图为例,当P0.6引脚上BUZ功能和LED功能同时选中时,引脚输出LED波形。

“中颖8bit

当允许端口复用为其它功能时,用户可以修改PxCR﹑PxPCR,但在复用的其它功能被禁止前,这些操作不会影响端口状态。

当允许端口复用为其它功能时,任何对端口的读写操作只会影响到数据寄存器的值,端口引脚值保持不变,直到复用的其它功能关闭。

3、 I/O开漏模式介绍:

“中颖8bit

在I/O章节有选择N沟道开漏功能的寄存器时,可以实现I/O的N沟道开漏功能(注意上图红线处,IO管脚的电压不得超过VDD+0.3V电压)

如果I/O章节没有该选项的寄存器,但是又有TWI通讯功能,那么在TWI功能开启时,引脚自动切换成N沟道开沟。关闭TWI功能,自动切换回普通I/O。

芯片的电源输入端建议加去耦电路,防止VDD端出现瞬间的高压引入导致的电路损坏。

4、施密特及TTL功能介绍:

施密特功能介绍:

施密特输入特性是输入高电平阈值为0.8VDD,输入低电平阈值为0.2VDD。

VDD=5V举例,输入高电平>=4V,端口读取的电平为高,输入低电平<=1V,端口读取的电平为低。相对应的引脚是否具有施密特功能,请查询电气特性章节(输入高电压2和输入低电压2中注明有施密特功能的引脚,例如INT0-4,T3-T5等)。普通I/O不具有施密特功能。

TTL功能介绍:

TTL电平输入特性是

1) 输入高电平阈值为0.25VDD+0.8,输入低电平阈值为0.15VDD(VDD=2.7V~4.5V)

以VDD=3.3V举例,输入高电平>=1.625V,端口读取的电平为高,输入低电平<=0.495V,端口读取的电平为低。

2)输入高电平阈值为2.0V,输入低电平阈值为0.8V(VDD=4.5V~5.5V)

以VDD=5 V举例,输入高电平>=2V,端口读取的电平为高,输入低电平<=0.8V,端口读取的电平为低。

选择TTL电平功能可与VDD电压为3.3V的WIFI模块直接通过以Uart或者TWI的方式通讯,又或者直接接收外部中断信号(INT0-4),不需要外加电平转换电路。(芯片是否有TTL功能请查询I/O章节及电气特性章节)

端口输入模式选择寄存器如下(TTL和CMOS选择)

“中颖8bit

“中颖8bit

*:CPU在任何情况下,读取端口数据寄存器(P0,P1……),其输入高电平阈值为0.7VDD,输入低电平阈值为0.3VDD(CMOS逻辑,无施密特);该控制位控制的是其他功能输入的逻辑电平状态,例如:INT0 - 4,RXD,SDA等数字电平输入。

注意:TTL电平特性,详情请见规格书电气特性章节。

来源:中颖电子
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 128

Microchip Technology Inc.(资深应用工程技术顾问Bob Martin)

当前,在从搅拌机到牙刷的一切设备都连接到云端的狂热浪潮中,物联网领域正由低成本的集成32位单片机RF模块控制,这些模块为少量传感器输入提供小尺寸解决方案。

Wi-Fi®、NB IoT和Bluetooth®的通信协议栈非常适合32位领域,同时还能提高计算能力以确保RF通道安全。但是,随着传感器通道数量的增加或更多偏远地点所需的功耗降低,会增加系统设计的复杂性,此时按如下方式添加额外的8位MCU可以增加价值,如图1所示:

真正的5V IO支持和传感器聚合

工业环境仍以5V电源生态系统为主,虽然有完全支持5V电压的32位MCU,但大多数集成32位MCU/RF为仅支持3.3V电源域的器件。在5V电源域中,允许通过GPIO更高效的8位MCU直接连接到5V电源传感器、开关触点和执行器,而无需添加多个电平转换器或调整模拟电压输入来满足3.3V电压要求。

现在,只需对8位MCU和32位MCU/RF模块之间的通信通道进行电平转换/调整操作。在32位MCU模块具有5V耐压输入的某些情况下,可能根本不需要电平转换,也许只需要一些串联电阻隔离。对于还需要电流隔离的情况,通过减少需要保护系统RF部分的专用IC的数量可节省更多成本。

远程安装通常需要更高的容错能力,这可能会导致使用多个传感器或执行器控制来减轻现场故障带来的影响。冗余传感器接口连接意味着,引脚有限的32位MCU/RF模块上存在更多输入/输出引脚分配问题。8位MCU往往会提供巨大的接口引脚密度,从而允许在前端的传感器阵列中添加一些智能容错功能。它不需要利用机器学习算法来确定三个温度传感器中是否有一个发生故障。这些类型的决策可以通过更快的事件响应在本地做出。

“工业传感器集成
工业传感器集成 © xiaoliangge - stock.adobe.com

图1——8位/32位系统分区

“物联网领域里的8位单片机:用传统芯片简化高级架构接口"

系统分区

使用外部8位MCU与大多数传感器接口,可以轻松地将已知的工作模拟/数字前端快速接入不同的RF模块后端。集成32位MCU/RF模块通常随附大量示例应用程序,这些应用程序展示出连接到云是举手之劳,无需考虑供应商。应用程序示例中可能未明确说明如何与标准I2C或SPI总线之外的传感器或执行器接口。经过验证的已知传感器/控制前端具有一致且定义明确的接口,通过最大限度地简化移植过程,还可以更灵活地选择合适的RF模块。一旦新RF模块上的新物理层支持两个MCU之间的协议层,新系统的集成工作便已基本完成。现在,可以将开发工作的重点放在新RF通道的正确实现上。

具有容错热插拔接口的松耦合系统是工业或远程环境设置中的一项有益特性。有时,整体系统交换无法避免,但最理想的选择是尽量减少对已知可靠系统的整体更改。这种松耦合还可让受信任的已知RF平台支持扩展的系统需求,而无需从头开始。保留您信任的部分,改进有所不足的部分。

“系统分区和架构
系统分区和架构 © myboys.me - stock.adobe.com

智能电源管理

遗憾的是,转向更小型IC栅极技术需要在速度和静态电流泄漏之间做出权衡。新制程节点中的栅极氧化层厚度即将达到以原子数而非纳米数计算的最佳厚度。8位MCU领域由更大的制程工艺主导,这些工艺可实现更出色的静态泄漏率。由于最佳低功耗管理技术从定义上来说就是同时切断电源,因此添加智能低功耗管理器件可以改善低功耗运行。一些8位MCU器件的工作电流运行在标准32.768 kHz晶振下,而此晶振会在32位RF模块上泄漏电流。这种方法现在增加了基于精确时间的电源管理系统,还拥有为电池充电和监视电池运行状况的能力。32位RF模块(特别是基于Wi-Fi的单元)的有功电流可以达到数百毫安。如果电池组电量即将耗尽,可能无法维持连接到网络所需的启动和传输电流。

基于8位MCU的电源管理系统现在可以使用特殊的唤醒命令来唤醒主RF模块,此命令可降低所需的电流需量,从而使RF模块以最佳相序保持在线。现在,这种特殊唤醒用例可以使用降低TX功率的方法来最终建立到网络的连接。8位MCU电源管理系统可以定期监视峰值启动电流和电压下降,并在每个唤醒周期提交这些数据。适当的云机器学习引擎可以利用这些数据来更好地分析电池系统并预测故障。

“低功耗远程应用
低功耗远程应用 © aquatarkus - stock.adobe.com

编程模型/MCU复杂性

在过去几年中,32位MCU/RF模块的编程难度显著降低。其中一些模块提供基于Arduino的支持,这肯定有助于加快开发速度,但当涉及到更多客户传感器、电源管理或其他外设接口时,编程难度会提高。Arduino支持代码十分庞大,但在许多情况下并不完整,并且在专业领域仍然存在一些信任问题。此外,IC供应商本身也提供支持,但归根结底,无法避免在裸金属层集成32位RF模块带来的额外复杂性。所有基于32位的控制寄存器对于一些控制位或状态位来说似乎都太大了,尽管转向32位时确实会发生这种情况,但在目前,并非所有人都能在像0x23AA123C这样的外设控制值中直观地挑出错误的位。

8位MCU编程模型以8位区块的形式呈现常见的接口,有时会扩展到16位以便用于定时器寄存器。除了能够更轻松地调试位域外,8位MCU上的外设集往往更易于理解,因为它们不需要涉及或提供更复杂的降低功耗或总线接口同步功能。8位MCU中的时钟树也更易于理解,即使在时钟树中提供PLL,操作也更加简单。然而,这正是使用8位MCU配套器件的全部意义所在,提供低功耗、低成本、智能但不能流畅支持物联网的器件,以处理所有后台、电源管理和繁琐的任务。

Microchip提供了几个8位MCU器件的示例,包括PIC18-Q41系列和AVR DB系列。这两个系列均提供大量模拟功能,包括片上运算放大器和多电平电压GPIO,减少了对额外的外部模拟元件和电平转换器的需求。

虽然可用的多核32位MCU/RF模块的数量在不断增加,但在物联网环境中,设计稳健的低功耗边缘节点时,添加8位MCU仍然是可行的选择。它们以小型封装形式提供电源和传感器管理,因此仍然在32位物联网领域发挥着重要作用。

围观 30

一、定义

1、上拉就是将不确定的信号通过一个电阻嵌位在高电平!“电阻同时起限流作用”!下拉同理!

2、上拉是对器件注入电流,下拉是输出电流

3、弱强只是上拉电阻的阻值不同,没有什么严格区分

4、对于非集电极(或漏极)开路输出型电路(如普通门电路)提升电流和电压的能力是有限的,上拉电阻的功能主要是为集电极开路输出型电路输出电流通道。

二、上拉电阻作用

1、一般作单键触发使用时,如果IC本身没有内接电阻,为了使单键维持在不被触发的状态或是触发后回到原状态,必须在IC外部另接一电阻。

2、数字电路有三种状态:高电平、低电平、和高阻状态,有些应用场合不希望出现高阻状态,可以通过上拉电阻或下拉电阻的方式使处于稳定状态,具体视设计要求而定!

4、上拉电阻是用来解决总线驱动能力不足时提供电流的。一般说法是拉电流,下拉电阻是用来吸收电流的,也就是我们通常所说的灌电流

5、接电阻就是为了防止输入端悬空

6、减弱外部电流对芯片产生的干扰

7、保护cmos内的保护二极管,一般电流不大于10mA

8、通过上拉或下拉来增加或减小驱动电流

9、改变电平的电位,常用在TTL-CMOS匹配

10、在引脚悬空时有确定的状态

11、增加高电平输出时的驱动能力。

12、为OC门提供电流

三、上拉电阻应用原则

1、当TTL电路驱动COMS电路时,如果TTL电路输出的高电平低于COMS电路的 高电平(一般为3。5V),这时就需要在TTL的输出端接上拉电阻,以提高输出高电平的值。

2、OC门电路“必须加上拉电阻,才能使用”。

3、为加大输出引脚的驱动能力,有的单片机管脚上也常使用上拉电阻。

4、在COMS芯片上,为了防止静电造成损坏,不用的管脚不能悬空,一般接上拉电阻产生降低输入阻抗,提供泄荷通路。

5、芯片的管脚加上拉电阻来提高输出电平,从而提高芯片输入信号的噪声容限增强抗干扰能力。

6、提高总线的抗电磁干扰能力。管脚悬空就比较容易接受外界的电磁干扰。

7、长线传输中电阻不匹配容易引起反射波干扰,加上下拉电阻是电阻匹配,有效的抑制反射波干扰。

8、在数字电路中不用的输入脚都要接固定电平,通过1k电阻接高电平或接地。

四、上拉电阻阻值选择原则

1、从节约功耗及芯片的灌电流能力考虑应当足够大;电阻大,电流小。

2、从确保足够的驱动电流考虑应当足够小;电阻小,电流大。

3、对于高速电路,过大的上拉电阻可能边沿变平缓。综合考虑

以上三点,通常在1k到10k之间选取。对下拉电阻也有类似道理。

对上拉电阻和下拉电阻的选择应“结合开关管特性和下级电路的输入特性进行设定,主要需要考虑以下几个因素”:

1、驱动能力与功耗的平衡。以上拉电阻为例,一般地说,上拉电阻越小,驱动能力越强,但功耗越大,设计是应注意两者之间的均衡。

2、下级电路的驱动需求。同样以上拉电阻为例,当输出高电平时,开关管断开,上拉电阻应适当选择以能够向下级电路提供足够的电流。

3、高低电平的设定。不同电路的高低电平的门槛电平会有不同,电阻应适当设定以确保能输出正确的电平。以上拉电阻为例,当输出低电平时,开关管导通,上拉电阻和开关管导通电阻分压值应确保在零电平门槛之下。

4、频率特性。以上拉电阻为例,上拉电阻和开关管漏源级之间的电容和下级电路之间的输入电容会形成“RC延迟”,电阻越大,延迟越大。上拉电阻的设定应考虑电路在这方面的需求。

下拉电阻的设定的原则和上拉电阻是一样的。

OC门输出高电平时是一个高阻态,其上拉电流要由上拉电阻来提供,设输入端每端口不大于100uA,设输出口驱动电流约500uA,标准工作电压是5V,输入口的高低电平门限为0.8V(低于此值为低电平);2V(高电平门限值)。

选上拉电阻时:500uA x 8.4K= 4.2即选大于8.4K时输出端能下拉至0.8V以下,此为 阻值,再小就拉不下来了。如果输出口驱动电流较大,则阻值可减小,保证下拉时能低于0.8V即可。当输出高电平时,忽略管子的漏电流,两输入口需200uA,200uA x15K=3V即上拉电阻压降为3V,输出口可达到2V,此阻值为 阻值,再大就拉不到2V了。选10K可用。【 压降/ 电流、 压降/ 电流】

COMS门的可参考74HC系列设计时管子的漏电流不可忽略,IO口实际电流在不同电平下也是不同的,上述仅仅是原理,一句话概括为:“输出高电平时要喂饱后面的输入口,输出低电平不要把输出口喂撑了”,否则多余的电流喂给了级联的输入口,高于低电平门限值就不可靠了。

此外,还应注意以下几点:

A、要看输出口驱动的是什么器件,如果该器件需要高电压的话,而输出口的输出电压又不够,就需要加上拉电阻。

B、如果有上拉电阻那它的端口在默认值为高电平,你要控制它必须用低电平才能控制如三态门电路三极管的集电极,或二极管正极去控制把上拉电阻的电流拉下来成为低电平。

C、尤其用在接口电路中,为了得到确定的电平,一般采用这种方法,以保证正确的电路状态,以免发生意外,比如,在电机控制中,逆变桥上下桥臂不能直通,如果它们都用同一个单片机来驱动,必须设置初始状态,防止直通!

驱动尽量用灌电流。

电阻在选用时,选用经过计算后与标准值相近的一个!

P0为什么要上拉电阻原因有:

1、 P0口片内无上拉电阻

2、 P0为I/O口工作状态时,上方FET被关断,从而输出脚浮空,因此P0用于输出线时为开漏输出。

3、 由于片内无上拉电阻,上方FET又被关断,P0输出1时无法拉升端口电平。

P0是双向口,其它P1,P2,P3是准双向口。准双向口是因为在读外部数据时要先“准备”一下,为什么要准备一下呢?

单片机在读准双向口的端口时,先应给端口锁存器赋1,目的是使FET关断,不至于因片内FET导通使端口钳制在低电平。

上下拉一般选10k!

来源:畅学单片机
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:
cathy@eetrend.com)。

围观 212

对于平常日用的一些产品,产品在进行设计时就会考虑这个问题,客户只是简单的利用插头进行电源的连接,所以一般采用反插错接头,这是种简单,低价而有效的方法。

但是,对于产品处于工厂生产阶段,可能不便采用防差错接头,这可能就会造成由于生产人员的疏忽造成反接,带来损失。

所以给电路增加防接反电路有时还是有必要的,尽管增加了成本。

下面就说说常用的防接反电路:

1、最简单的在电路中串入一只二极管

“实用的单片机接反电路,再也不怕电源接反了"

优点:电路简单,成本较低。适用于小电流,对成本要求比较严的产品。

缺点:由于二极管的PN结在导通时,存在一个压降,一般在0.7V以下。这个压降就导致这种电路不适合应用在电流较大的电路中,如果电路有10A的电流,那么二极管的功耗就是0.7*10=7W,发热量还是很可观的。在结构紧凑空间有限的产品中,对产品的稳定性或人的使用感受上影响还是比较大的。

2、对于上面上面提到的二极管的压降问题,有没有办法克服呢?看下面的电路。

“实用的单片机接反电路,再也不怕电源接反了"

上面的防接反电路采用了一个保险丝和一个反向并联的二极管,电源极性正确,电路正常工作时,由于负载的存在电流较小,二极管处于反向阻断状态,保险丝不会被熔断。

当电源接反时,二极管导通,此时的电流比较大,就会将保险丝熔断,从而切断电源的供给,起到保护负载的作用。

优点:保险丝的压降很小,不存在发热问题。成本不高。

缺点:一旦接反需要更换保险丝,操作比较麻烦。

3、正接反接都可正常工作的电路:

“实用的单片机接反电路,再也不怕电源接反了"

优点:输入端无论怎样接,电路都可以正常工作。
缺点:存在两个二极管的压降。适用于小电流电路。

4、N沟道增强型场效应管防接反电路

由场效应管制作工艺决定了,场效应管的导通电阻比较小。是现在很常用的开关器件,特别是在大功率的场合。以TO-252封装的IRFR1205为例,其主要参数如下:Vdss=55V,Id=44A,Rds=0.027欧姆;可以看到其导通电阻只有27毫欧。

下图就是一个用N沟道场效应管构成的防接反电路

“实用的单片机接反电路,再也不怕电源接反了"

这个电路的最大一个特点就是场效应管的D极和S极的接法。通常我们在使用N沟道的增强型的MOS管时,一般是电流由D极进入而从S极流出。应用在这个电路中时则正好相反。

曾经在一个论坛中看到过这个电路,发布这个电路的楼主被众多网友痛批。说是DS之间存在一个二极管根本没法实现。楼主没有注明场效应管的管脚名称,由于存在一个应用场效应管的惯性思维,导致楼主蒙冤。

其实场效应管只要在G和S极之间建立一个合适的电压就会完全导通。导通之后D和S之间就像是一个开关闭合了,电流是从D到S或S到D都一样的电阻。

在电源极性正确时,电流起始时通过场效应管的稳压管导通,S极电压接近0V。

两个电阻分压后,为G提供电压,使场效应管导通,因为其导通阻值很小,就把场效应管内部的二极管给替代了。

电源反接时,场效应管内的二极管未到击穿电压不导通。分压电阻无电流流过无法提供G极电压,也不导通。从而起到保护作用。

对于电路中并联在分压电阻上的稳压二极管,因为场效应管的输入电阻是很高的,

是一个压控型器件,G极电压要控制在20V内,过高的电压脉冲会导致G极的击穿,这个稳压二极管就是起一个保护场效应管防止击穿的作用。

对于并联在分压电阻上的电容,有一个软启动的作用。在电流开始流过的瞬间,电容充电,G极的电压是逐步建立起来的。

对于并联在场效应管D与S之间的阻容串联电路,我感觉还是值得商榷的。阻容串联电路一般用作脉冲吸收或延时。用在这里要视负载的情况而定,加了或许反而不好。毕竟这会导致在电源在反接的时候会有一个短暂的导通脉冲。

也可以用P沟道的场效应管,只是要将器件串在正极的输入端。这里不再描述。

来源:小麦大叔
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:
cathy@eetrend.com)。

围观 102

页面

订阅 RSS - 单片机