单片机

前阵子一朋友使用单片机与某外设进行通信时,外设返回的是一堆格式如下的数据:

AA AA 04 80 02 00 02 7B AA AA 04 80 02 00 08 75 AA AA 04 80 02 00 9B E2 AA AA 04 80 02 00 F6 87 AA AA 04 80 02 00 EC 91

其中 AA AA 04 80 02 是数据校验头,后面三位是有效数据,问我怎么从外设不断返回的数据中取出有效的数据。

对于这种问题最容易想到的就是使用一个标志位用于标志当前正解析到一帧数据的第几位,然后判断当前接收的数据是否与校验数据一致,如果一致则将标志位加一,否则将标志位置0重新判断,使用这种方法解析数据的代码如下:

if(flag == 0)
{
	if(tempData == 0xAA)
		flag++;
	else
		flag = 0;
}
else if(flag == 1)
{
	if(tempData == 0xAA)
		flag++;
	else
		flag = 0;
}
else if(flag == 2)
{
	if(tempData == 0x04)
		flag++;
	else
		flag = 0;
}
else if(flag == 3)
{
	if(tempData == 0x80)
		flag++;
	else
		flag = 0;
}
else if(flag == 4)
{
	if(tempData == 0x02)
		flag++;
	else
		flag = 0;
}
else if(flag == 5 || flag == 6 || flag == 7)
{
	data[flag-5] = tempData;
	flag = (flag == 7) ? 0 : flag+1;
}

使用上述方法是最容易想到的也是最简单的方法了,百度了一下基本上也都是使用类似的方法进行数据解析,但是使用这种方法有如下几个缺点:

1、 大量使用了判断,容易导致出现逻辑混乱

2、 代码重复率高,抽象程度低。从上述代码可以看到一大堆代码仅仅是判断的数据不同,其他代码都完全一致

3、 代码可复用性差。写好的代码无法用在其他类似的外设上,如果有多个外设就需要编写多份类似的代码

4、 可扩展性低。如果外设还有一个数据校验尾需要校验或者数据校验头发生改变,就需要再次写多个判断重新用于校验,无法在原有的代码上进行扩展

5、 容易出现误判

对此,这里提出了一种新的解决方案,可以通用与所有类似的数据解析,原理如下:

使用一个固定容量的队列用来缓存接收到的数据,队列容量等于一帧数据的大小,每来一个数据就将数据往队列里面加,当完整接收到一帧数据时此时队列中的全部数据也就是一帧完整的数据,因此只需要判断队列是否是数据校验头,队列尾是否是数据校验尾就可以得知当前是否已经接收到了一帧完整的数据,然后在将数据从队列中取出即可。原理图如下:

每来一个数据就往队列里面加:

“单片机接收数据帧帧头帧尾校验数据解析"

当接收到一帧完整数据时队列头和数据校验头重合:

“单片机接收数据帧帧头帧尾校验数据解析"

此时只需要从队列中取出有效数据即可。

如果有数据尾校验,仅仅只需要添加一个校验尾即可,如下图所示:

“单片机接收数据帧帧头帧尾校验数据解析"

好,分析结束,开始编码。

首先需要一个队列,为了保证通用性,队列底层使用类似于双向链表的实现(当然也可以使用数组实现),需要封装的结构有队列容量、队列大小、队头节点和队尾节点,需要实现的操作有队列初始化、数据入队、数据出队、清空队列和释放队列,具体代码如下:

/* queue.h */
 
#ifndef _QUEUE_H_
#define _QUEUE_H_
 
#ifndef NULL
#define	NULL	((void *)0)
#endif
 
typedef unsigned char uint8;
 
/* 队列节点 */
typedef struct Node
{
	uint8 data;
	struct Node *pre_node;
	struct Node *next_node;
} Node;
 
/* 队列结构 */
typedef struct Queue
{
	uint8 capacity;     // 队列总容量
	uint8 size;         // 当前队列大小
	Node *front;        // 队列头节点
	Node *back;         // 队列尾节点
} Queue;
 
/* 初始化一个队列 */
Queue *init_queue(uint8 _capacity);
/* 数据入队 */
uint8 en_queue(Queue *_queue, uint8 _data);
/* 数据出队 */
uint8 de_queue(Queue *_queue);
/* 清空队列 */
void clear_queue(Queue *_queue);
/* 释放队列 */
void release_queue(Queue *_queue);
 
#endif
/* queue.c */
 
#include <stdlib.h>
#include "parser.h"
 
/**
 * 初始化一个队列
 *
 * @_capacity: 队列总容量
 */
Queue *init_queue(uint8 _capacity)
{
	Queue *queue = (Queue *)malloc(sizeof(Queue));
	queue->capacity = _capacity;
	queue->size = 0;
	return queue;
}
 
/**
 * 数据入队
 *
 * @_queue: 队列
 * @_data: 数据
 **/
uint8 en_queue(Queue *_queue, uint8 _data)
{
	if(_queue->size < _queue->capacity)
	{
		Node *node = (Node *)malloc(sizeof(Node));
		node->data = _data;
		node->next_node = NULL;
 
        if(_queue->size == 0)
        {
            node->pre_node = NULL;
            _queue->back = node;
            _queue->front = _queue->back;
        }
        else
        {
            node->pre_node = _queue->back;
 
            _queue->back->next_node = node;
            _queue->back = _queue->back->next_node;
        }
		_queue->size++;
	}
	else
	{
		Node *temp_node = _queue->front->next_node;
		_queue->front->pre_node = _queue->back;
		_queue->back->next_node = _queue->front;
		_queue->back = _queue->back->next_node;
		_queue->back->data = _data;
		_queue->back->next_node = NULL;
		_queue->front = temp_node;
	}
	return _queue->size-1;
}
 
/**
 * 数据出队
 *
 * @_queue: 队列
 *
 * @return: 出队的数据
 */
uint8 de_queue(Queue *_queue)
{
    uint8 old_data = 0;
 
    if(_queue->size > 0)
    {
        old_data = _queue->front->data;
        if(_queue->size == 1)
        {
            free(_queue->front);
            _queue->front = NULL;
            _queue->back = NULL;
        }
        else
        {
            _queue->front = _queue->front->next_node;
            free(_queue->front->pre_node);
            _queue->front->pre_node = NULL;
        }
        _queue->size--;
    }
    return old_data;
}
 
/**
 * 清空队列
 *
 * @_queue: 队列
 */
void clear_queue(Queue *_queue)
{
    while(_queue->size > 0)
    {
        de_queue(_queue);
    }
}
 
/**
 * 释放队列
 *
 * @_queue: 队列
 */
void release_queue(Queue *_queue)
{
    clear_queue(_queue);
    free(_queue);
    _queue = NULL;
}

其次是解析器,需要封装的结构有解析数据队列、数据校验头、数据校验尾、解析结果以及指向解析结果的指针,需要实现的操作有解析器初始化、添加数据解析、获取解析结果、重置解析器和释放解析器,具体代码如下:

/* parser.h */
 
#ifndef _PARSER_H_
#define _PARSER_H_
 
#include "queue.h"
 
typedef enum
{
    RESULT_FALSE,
    RESULT_TRUE
} ParserResult;
 
/* 解析器结构 */
typedef struct DataParser
{
    Queue *parser_queue;			// 数据解析队列
    Node *resule_pointer;			// 解析结果数据指针
    uint8 *data_header;				// 数据校验头指针
    uint8 header_size;				// 数据校验头大小
    uint8 *data_footer;				// 数据校验尾指针
    uint8 footer_size;				// 数据校验尾大小
    uint8 result_size;				// 解析数据大小
    ParserResult parserResult;		// 解析结果
} DataParser;
 
/* 初始化一个解析器 */
DataParser *parser_init(uint8 *_data_header, uint8 _header_size, uint8 *_data_footer, uint8 _foot_size, uint8 _data_frame_size);
/* 将数据添加到解析器中进行解析 */
ParserResult parser_put_data(DataParser *_parser, uint8 _data);
/* 解析成功后从解析器中取出解析结果 */
int parser_get_data(DataParser *_parser, uint8 _index);
/* 重置解析器 */
void parser_reset(DataParser *_parser);
/* 释放解析器 */
void parser_release(DataParser *_parser);
 
#endif
/* parser.c */
 
#include <stdlib.h>
#include "parser.h"
 
/**
 * 初始化一个解析器
 *
 * @_data_header: 数据头指针
 * @_header_size: 数据头大小
 * @_data_footer: 数据尾指针
 * @_foot_size: 数据尾大小
 * @_data_frame_size: 一帧完整数据的大小
 *
 * @return: 解析器
 */
DataParser *parser_init(uint8 *_data_header, uint8 _header_size, uint8 *_data_footer, uint8 _foot_size, uint8 _data_frame_size)
{
    if((_header_size+_foot_size) > _data_frame_size || (_header_size+_foot_size) == 0)
        return NULL;
 
    DataParser *parser = (DataParser *)malloc(sizeof(DataParser));
    parser->parser_queue = init_queue(_data_frame_size);
    parser->resule_pointer = NULL;
    parser->data_header = _data_header;
    parser->header_size = _header_size;
	parser->data_footer = _data_footer;
	parser->footer_size = _foot_size;
    parser->result_size = _data_frame_size - parser->header_size - parser->footer_size;
    parser->parserResult = RESULT_FALSE;
 
    while(_data_frame_size-- > 0)
    {
        en_queue(parser->parser_queue, 0);
    }
 
    return parser;
}
 
/**
 * 将数据添加到解析器中进行解析
 *
 * @_parser: 解析器
 * @_data: 要解析的数据
 *
 * @return: 当前解析结果,返回 RESULT_TRUE 代表成功解析出一帧数据
 */
ParserResult parser_put_data(DataParser *_parser, uint8 _data)
{
    uint8 i;
    Node *node;
 
	if(_parser == NULL)
		return RESULT_FALSE;
 
    en_queue(_parser->parser_queue, _data);
 
	/* 校验数据尾 */
	node = _parser->parser_queue->back;
	for(i = _parser->footer_size; i > 0; i--)
	{
		if(node->data != _parser->data_footer[i-1])
            goto DATA_FRAME_FALSE;
        node = node->pre_node;
	}
 
	/* 校验数据头 */
    node = _parser->parser_queue->front;
    for(i = 0; i < _parser->header_size; i++)
    {
        if(node->data != _parser->data_header[i])
            goto DATA_FRAME_FALSE;
        node = node->next_node;
    }
 
    if(_parser->resule_pointer == NULL && _parser->result_size > 0)
        _parser->resule_pointer = node;
    if(_parser->parserResult != RESULT_TRUE)
    	_parser->parserResult = RESULT_TRUE;
    return _parser->parserResult;
 
DATA_FRAME_FALSE:
    if(_parser->resule_pointer != NULL)
        _parser->resule_pointer = NULL;
    if(_parser->parserResult != RESULT_FALSE)
        _parser->parserResult = RESULT_FALSE;
    return _parser->parserResult;
 
}
 
/**
 * 解析成功后从解析器中取出解析结果
 *
 * @_parser: 解析器
 * @_index: 解析结果集合中的第 _index 个数据
 *
 * @return: 获取解析成功的数据,返回 -1 代表数据获取失败
 */
int parser_get_data(DataParser *_parser, uint8 _index)
{
    Node *node;
    if(_parser == NULL
	|| _parser->parserResult != RESULT_TRUE
    || _index >= _parser->result_size
    || _parser->resule_pointer == NULL)
        return -1;
    node = _parser->resule_pointer;
    while(_index > 0)
    {
        node = node->next_node;
        _index--;
    }
    return node->data;
}
 
/**
 * 重置解析器
 *
 * @_parser: 解析器
 */
void parser_reset(DataParser *_parser)
{
	uint8 _data_frame_size;
 
	if(_parser == NULL)
		return;
 
	_data_frame_size = _parser->parser_queue->size;
	while(_data_frame_size-- > 0)
    {
        en_queue(_parser->parser_queue, 0);
    }
    _parser->resule_pointer = NULL;
    _parser->parserResult = RESULT_FALSE;
}
 
/**
 * 释放解析器
 *
 * @_parser: 解析器
 */
void parser_release(DataParser *_parser)
{
	if(_parser == NULL)
		return;
    release_queue(_parser->parser_queue);
    free(_parser);
    _parser = NULL;
}

接下来编写测试代码测试一下:

/* main.c */
 
#include <stdio.h>
#include "parser.h"
 
int main()
{
    uint8 i;
    // 数据头
    uint8 data_header[] = {0xAA, 0xAA, 0x04, 0x80, 0x02};
    // 要解析的数据,测试用
    uint8 data[] = {
        0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x02, 0x7B, 0xAA, 0xAA, 0x04, 0x80,
        0x02, 0x00, 0x08, 0x75, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x9B, 0xE2,
        0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0xF6, 0x87, 0xAA, 0xAA, 0x04, 0x80,
        0x02, 0x00, 0xEC, 0x91, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x15, 0x67,
        0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x49, 0x33, 0xAA, 0xAA, 0x04, 0x80,
        0x02, 0x00, 0xE7, 0x96, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x68, 0x15,
        0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0x3C, 0x41, 0xAA, 0xAA, 0x04, 0x80,
        0x02, 0x00, 0x66, 0x17, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0xA5, 0xD8,
        0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x26, 0x56, 0xAA, 0xAA, 0x04, 0x80,
        0x02, 0x01, 0x73, 0x09, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x64, 0x18,
        0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x8B, 0xF1, 0xAA, 0xAA, 0x04, 0x80,
        0x02, 0x01, 0xC6, 0xB6, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0x01, 0x7B, 0x01,
        0xAA, 0xAA, 0x04, 0x80, 0x02, 0x00, 0xCB, 0xB2, 0xAA, 0xAA, 0x04, 0x80,
        0x02, 0x00, 0x2C, 0x51, 0xAA, 0xAA, 0x04, 0x80, 0x02, 0xFF, 0xE5, 0x99
    };
 
    /**
     * 初始化一个解析器
     * 第一个参数是数据头
     * 第二个参数是数据头长度
     * 第三个参数是数据尾指针
     * 第四个参数是数据尾大小
     * 第五个参数是一整帧数据的大小
     */
    DataParser *data_parser = parser_init(data_header, sizeof(data_header), NULL, 0, 8);
 
    // 将要解析的数据逐个取出,添加到解析器中
    for(i = 0; i < sizeof(data); i++)
    {
        // 解析数据,返回 RESULT_TRUE 代表成功解析出一组数据
        if(parser_put_data(data_parser, data[i]) == RESULT_TRUE)
        {
            printf("成功解析出一帧数据...\n");
 
            /* 一位一位取出解析后的数据 */
            printf("第一个数据是:0x%x\n", parser_get_data(data_parser, 0));
            printf("第二个数据是:0x%x\n", parser_get_data(data_parser, 1));
            printf("第三个数据是:0x%x\n\n\n", parser_get_data(data_parser, 2));
        }
    }
 
    // 当不再需要解析器时,应该把解析器释放掉,回收内存,避免造成内存泄漏
    parser_release(data_parser);
 
    return 0;
}

测试结果如下:

“单片机接收数据帧帧头帧尾校验数据解析"

从上面可以看出,解析的结果与目标一致。

github地址:https://github.com/528787067/DataFrameParser
————————————————
版权声明:本文为CSDN博主「XR528787067」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/XR528787067/article/details/52822377
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 25

对于嵌入式系统,如果没有运行RTOS,那么程序开发中的主函数main()需要通过某种机制使其永远愉快的运行下去,它没有终点。如果想从main函数中退出,具体干什么是由所使用的C语言编译器决定的。

一、问题提出

今天在单片机led模块定义函数中看到一个有趣的问题。提问者在进行基本的C51编程实验,编写了一个简单的C51程序如下:

#include <REGX51.H>

void test(num) {
    switch(num) {
        case 1: P2_0=0; P2_1=0; 
            break;
    }
}

void main(void) {
    test(1);
}

程序执行完之后,可以看到实验板上的有两个LED被点亮,另外六个居然微微发亮。

“单片机的程序结束后都干嘛去了?"

如果在主程序中,增加一个无限循环:while(1); ,则电路板上的就不再会出现“微微点亮”的现象了。

#include <REGX51.H>

void test(num) {
    switch(num) {
        case 1: P2_0=0; P2_1=0; 
            break;
    }
}

void main(void) {
    test(1);
    while(1);
}

“单片机的程序结束后都干嘛去了?"

上面两种情况的区别,在于第二个程序中主循环 main()函数始终没有退出,而第一个程序,main()函数退出了。似乎前面LED微微点亮 应该与主函数退出之后,单片机都干了些啥有关系。

那么就剩下一个问题:对于普通的嵌入式系统,C语言编程中main()函数退出之后,程序去哪儿了?

二、程序去哪儿了?

从上面提问者书写的代码来看,应该是一位C51的爱好者,使用的是C51的编译器,在一款C51开发板上愉快的进行实验。他一开始没有安装嵌入式程序开发的惯例 在主程序void main(void)中利用无限循环将程序控制在主程序函数中,就出现了前面实验结果中令人迷惑的情况。

“注:他是一个胆大心细的人,观察还挺仔细的。”

2.1 盘古开天辟地

对于C语言编程来说,所有的用户程序世界是从主程序main()开始的。给用户程序开天辟地的任务是由一小段盘古代码STARTUP.A51。

51单片机程序执行流程(STARTUP.A51管理Main函数的执行)

下面截取了STARTUP.A51 代码的一段,可以看到盘古在单片机RESET之后做了点准备工作(初始化全局变量、堆栈指针)之后,就直接跳转至:?C_START

NAME    ?C_STARTUP

?C_C51STARTUP   SEGMENT   CODE
?STACK          SEGMENT   IDATA

                RSEG    ?STACK
                DS      1

                EXTRN CODE (?C_START)
                PUBLIC  ?C_STARTUP

                CSEG    AT      0
?C_STARTUP:     LJMP    STARTUP1

                RSEG    ?C_C51STARTUP

STARTUP1:

IF IDATALEN <> 0
                MOV     R0,#IDATALEN - 1
                CLR     A
IDATALOOP:      MOV     @R0,A
                DJNZ    R0,IDATALOOP
ENDIF

IF XDATALEN <> 0
                MOV     DPTR,#XDATASTART
                MOV     R7,#LOW (XDATALEN)
  IF (LOW (XDATALEN)) <> 0
                MOV     R6,#(HIGH (XDATALEN)) +1
  ELSE
                MOV     R6,#HIGH (XDATALEN)
  ENDIF
                CLR     A
XDATALOOP:      MOVX    @DPTR,A
                INC     DPTR
                DJNZ    R7,XDATALOOP
                DJNZ    R6,XDATALOOP
ENDIF

IF PPAGEENABLE <> 0
                MOV     PPAGE_SFR,#PPAGE
ENDIF

IF PDATALEN <> 0
                MOV     R0,#LOW (PDATASTART)
                MOV     R7,#LOW (PDATALEN)
                CLR     A
PDATALOOP:      MOVX    @R0,A
                INC     R0
                DJNZ    R7,PDATALOOP
ENDIF

IF IBPSTACK <> 0
EXTRN DATA (?C_IBP)

                MOV     ?C_IBP,#LOW IBPSTACKTOP
ENDIF

IF XBPSTACK <> 0
EXTRN DATA (?C_XBP)

                MOV     ?C_XBP,#HIGH XBPSTACKTOP
                MOV     ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF

IF PBPSTACK <> 0
EXTRN DATA (?C_PBP)
                MOV     ?C_PBP,#LOW PBPSTACKTOP
ENDIF

                MOV     SP,#?STACK-1
                LJMP    ?C_START

                END
上面的代码也被博文51单片机程序执行流程(STARTUP.A51)中进行逐步调试跟踪验证过:

“单片机的程序结束后都干嘛去了?"

2.2 世界尽头

由于进入main()函数是长跳转,所以main函数是不会正常返回到启动程序STARTUP.A51,那么程序去哪了?

在博文单片机C语言while(1)的问题中作者对于KEIL编译器和PIC的MAPLAB编译器对于main函数的最后时光进行了反汇编查看。

Keil编译器

在main函数的最后,程序增加了一下几行代码:

MOV R0, #0x7F
CLR A
MOV @R0, A
DJNZ R0, (3)
MOV SP, #0x0C
LJMP main
这几条语句,前4条,是将我们单片机的内存的前128个地址清零,第5条,是定义堆栈,第6条,是将程序重新跳转到main函数的首行进行执行。

MAPLAB编译器

PIC 单片机语言程序进行跟踪,发现main() 函数最后一条语句为 reset,也就是单片机直接复位,这是 MAPLAB编译器根据 PIC 单片机特点增加的复位语句。

总结

对于嵌入式系统,如果没有运行RTOS,那么程序开发中的主函数(main())需要通过某种机制使其永远愉快的运行下去,它没有终点。如果想从main函数中退出,具体干什么是由所使用的C语言编译器决定的。

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

围观 47

Cortex-M0处理器允许两种形式的中断请求:电平触发和脉冲输入。

电平触发是外设的中断请求有持续的电平信号,若电平信号在处理器从ISR返回之前没有被取消,则中断返回后将再次触发已经服务过的中断。

脉冲中断是在信号的上升沿同步采样的中断信号,为了确保NVIC检测到中断,外设必须维持中断信号至少一个时钟周期,在此期间,NVIC检测脉冲和锁存中断。后续的脉冲可以将暂挂状态加到活动中断中,使状态为中断活动且挂起。然而,在有限周期内发生的多个脉冲只登记作为中断调度的单个事件。

哪些中断是电平触发的,哪些是脉冲触发的,具体选择哪一种是根据芯片设计来决定,不过大多数的外设使用电平触发中断输出。

1. 电平触发和脉冲输入

Cortex-M0处理器锁存所有中断,外围中断成为等待其中一个原因是:

  • NVIC检测到中断信号被置位并且对应的中断不是active

  • NVIC检测到中断信号的上升沿

  • 软件写入相应的中断集挂起寄存器位

挂起的中断将一直挂起,直到下列情况之一发生:

  • 处理器为中断进入ISR,这将改变中断的状态等待活跃:

对于电平触发型中断,当处理器从ISR返回时,NVIC采样中断信号。如果中断信号仍然有效,表示中断的状态更改为pending,这可能会导致处理器立即重新进入ISR。否则,中断的状态将变为非活动状态。

对于脉冲触发型中断,NVIC继续监视中断信号,如果这样触发时,中断状态变为挂起和活动状态。在这种情况下,当处理器从ISR返回中断状态时,中断状态变为挂起状态可能会导致处理器立即重新进入ISR。如果中断信号不是脉冲而处理器是在ISR,当处理器从ISR返回中断状态变为非活动状态。

  • 软件写入相应的中断清除寄存器位。

对于电平触发型中断,如果中断信号仍然有效,则中断的状态中断不会改变。否则,中断的状态将变为非活动状态。

对于脉冲中断,中断状态变为:

  • inactive,如果状态是pending

  • active,如果状态是活动的和挂起的

2. 中断处理

当中断事件发生时,由于外设连接到了NVIC上,中断信号就会得到确认。在处理器执行中断服务并且没有清除外设的中断的信号以前,该信号会保持高电平。

在NVIC内部,当检测到有中断发生时,该中断的挂起状态会被置位,当处理器接受该中断并且开始执行中断服务后,挂起状态就会被清除。

“单片机中断电平触发和脉冲输入"

针对脉冲输入的中断请求,这种情况下,在中断得到服务之前,挂起状态寄存器将会一直保持该请求。

“单片机中断电平触发和脉冲输入"

如果中断请求没有立即执行,并且在确认之前被软件清除了,处理器将会忽略掉本次请求,并且不会执行中断处理。

如果在软件清除挂起状态时,外设仍然保持着中断请求,挂起状态寄存器还会立即生成。

3. 中断等待

通常情况下,处理器的中断等待时间为16个周期,这个等待时间从中断确认的处理器时钟周期开始,一直到中断处理开始执行结束。

计算中断等待需具备以下前提:

  • 该中断使能并没有PRIMASK或者其他正在执行的异常处理所屏蔽

  • 存储器系统没有任何等待状态,在中断处理、压栈、取向量表或者中断处理开始时取指都会用到总线传输,如果存储器系统需要等待,那么总线传输时产生的等待状态则可能使得中断延迟。

下面几种情况可能会导致不同的中断等待:

  • 中断的咬尾连锁,如果一个中断返回时立即产生另外一个中断请求,处理器就会跳过出栈和压栈时间,减少了中断等待时间。

  • 延迟到达,如果中断发生时,另外一个低优先级中断正在进行压栈处理,由于延迟到达,高优先级的中断就会立即执行,这样会导致高优先级的中断等待时间减少。

4. 异常屏蔽寄存器PRIMASK

有些对时间敏感的应用,需要在短时间内禁止响应所有的中断,对于这种应用,处理器不是直接使用中断使能、禁止控制寄存器来禁止所有中断再恢复,而是一个单独的特殊寄存器 - PRIMASK,通过它可以屏蔽掉除了NMI和HardFault异常的其他的所有的中断和系统异常。

PRIMASK寄存器只有1位有效,并且在复位后默认为0。该寄存器为0时,所有的中断和异常都处于允许状态,设置为1后,只有NMI和HardFault处于使能状态。

MOVS R0, #0x1         ;  //中断#2
MSR PRIMASK , R0       ;  //将R0的值送到PRIMASK

NVIC编程提示软件使用CPSIE i和CPSID i指令来启用和禁用中断。

CPSIE i                 ;  //清除 PRIMASK(使能中断)
CPSID i                 ;  //设置 PRIMASK(不响应中断)

CMSIS设备驱动库提供了C语言的实现函数,用户可以直接使用函数来设置和清除PRIMASK寄存器:

void __disable_irq(void) //不响应中断
void __enable_irq(void)  //启用中断

在对时间敏感的程序完成后,应该清除PRIMASK。要不然即使在中断处理中使用\_\_disable\_irq()函数,处理器将停止接受新的中断请求。主要原因是PRIMASK寄存器和Xpsr是相互独立的,因此异常返回不会影响中断屏蔽状态。

5. NVIC使用提示

确保软件使用正确对齐的寄存器访问,处理器不支持对 NVIC 寄存器的未对齐访问。

即使中断被禁用,它也可以进入挂起状态。

禁用中断只能防止处理器处理中断。

在对中断向量表重定义之前,必须包含所有的异常中断,例如 NMI、HardFault 和外设中断等。

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

围观 32

文章英文版出处:

https://www.eejournal.com/article/what-more-8-bit-microcontrollers/

以下全文转载自EEWeb主编Max Maxfield在EEJournal上发表的文章:

我们周围不断充斥着有关 8 位、16 位、32 位和 64 位处理器的讨论,我不确定如今还有多少年轻工程师知道第一个商用微处理器——英特尔4004。它是一台 4 位机器(部件编号虽然叫4004,却没有一语双关的意思)。

顺便说一句,如果您想了解更多关于 4004 以及当代微处理器的发展史,我衷心推荐我的朋友Steve Leibson在 EEJournal 上撰写的专栏文章:《我们是否真的知道是谁发明了微处理器?》和《哪个才是第一个微处理器?》以及《微处理器50岁生日快乐》的第1部分和第2部分。

微处理器(µP)也称为微处理器单元(MPU)。早期的 MPU 仅包含一个中央处理单元(CPU)。随着时间的推移,添加了其他功能,如高速缓存、浮点运算单元(FPU)以及存储管理单元(MMU)等。关键是:除了任何高速缓存以及 FPU 和 MMU 之类的东西,微处理器不包含任何内部存储器或外设。相比之下,单片机(µC),也称为微控制器单元(MCU),包含闪存等非易失性存储器,SRAM 等易失性存储器,计数器、定时器、模数转换器(ADC)等外设以及UART、I2C 和 SPI 等通信接口。从本质上讲,单片机是一种小型独立计算机,存在于包含自己的程序的单个硅芯片上。它一上电,程序就开始执行。这就解释了为什么单片机出现在嵌入式系统中,以及为什么嵌入式系统随处可见。(您可以通过我的专栏文章《CPU、MPU、MCU和GPU的常见问题解答有哪些?》,了解有关微处理器和单片机之间区别的更多信息)。

单片机的历史与微处理器的历史一样不甚明朗。第一个单片机是哪个?是日本人在1970 年代初为汽车制造的 4 位器件,还是 TI 工程师 Gary Boone 和 Michael Cochran设计并于 1974 年首次亮相的 4 位 TMS 1000?谈到 8 位 MCU,1976 年面市的英特尔 8048(又名 MCS-48)是第一个吗?我不知道。我所知道的是,早期 8 位 MCU 中最著名的可能是1980 年上市的 8051(又名 MCS-51),其指令集架构(ISA)由 John H. Wharton 构想。神奇的是,由8051演变出的新产品至今仍然强劲。

顺便说一句,John曾经告诉我,当他还是一名在英特尔工作的年轻工程师时,他经常和他的主管出去吃午饭。有一天,他们听说要在午餐时间开会讨论一些事情。他们不确定会议的重点是什么,只知道提供免费三明治。这个会议原来是 8051 的启动会。真的是完全从一张白纸开始的。会议结束后,John 饱餐了一顿,回到办公桌前,勾勒出 8051 的架构(功能单元和总线等)和 ISA。

如今,有众多的单片机能够实现我们的各类设想,而PIC®单片机和AVR®单片机是真正有存在感的两个系列。第一个 8 位 PIC MCU由 General Instruments 于 1975 年开发。我不确定它的具体发展史,但 PIC MCU现在是Microchip Technology Inc.的产品。同时,最初的 8 位 AVR 架构是由 Alf-Egil Bogen 和 Vegard Wollan 还是挪威理工学院(NTH)的学生时提出的。该技术随后被 Atmel 收购,该公司于 1996 年发布了 AVR 系列的第一批成员。 Atmel已于 2016 年被 Microchip收购。

我们有什么方法可以量化这种“存在感”?我曾经同Microchip 8位单片机产品部的营销副总裁 Greg Robinson 和资深公共关系经理Brian Thorsen 交流过。如下图所示,在撰写本文时,Microchip 的 8 位 MCU 市场份额为 32%,遥遥领先!如果我在Microchip负责这些产品的话,我肯定要笑逐颜开了。

“Gartner
Gartner 2021 市场份额报告中的全球 8 位单片机市场份额

Greg 告诉我,Microchip将持续创新,其中不乏许多8位新产品。例如,在 2022 年第二季度,Microchip推出了5 个全新系列,约 65 款器件,拥有丰富的片上模拟和其他独立于内核的外设。

除了传统的单芯片系统(即Microchip MCU是板上唯一的处理器)外,8位处理器作为系统管理IC和协处理器的作用也越来越大,尺寸、空间、低功耗和寿命等方方面面的特征都很重要。这在很大程度上是因为我们看到分布式智能在物联网边缘节点、汽车安全、工业控制系统、医疗电子和家用电子等应用领域的急剧增长。即使是最先进的 5G 系统,通常也可以从将某些任务分配给更小的 8 位处理器中受益,从而释放更高级处理器来发挥它们的魔力并做它们最擅长的事情。

Greg说:“尽管听起来很奇怪,很多 8 位的增长是由 32 位的增长推动的,其中 32 位处理器正在将人机界面(HMI)功能和内务管理任务等传递给8 位处理器。此外,8 位器件越来越多地用作协处理器,执行诸如获取传感器读数和预处理此传感器数据等任务,然后将其传递给更高级处理器。”

我们谈到的主题之一是当前的供应链问题。在我们交谈之前,我没有意识到Microchip 出货的 95% 的 8 位产品是内部制造的,而且除了在美国亚利桑那州Tempe、俄勒冈州Gresham和科罗拉多州Colorado Springs设有晶圆厂,他们还拥有自己的封装、制造和测试厂。

尽管如此,但由于贸易战和全球新冠疫情共同引发的大风暴,在过去 18 至 24 个月内产生了大量需求,因此仍然存在供货短缺的情况。Greg 说:“提高产量也不是嘴上一说这么简单。”Microchip 总裁兼首席执行官 Ganesh Moorthy 曾表示,他预计短缺将持续到 2023 年,但 Microchip 已承诺在未来几年会投入 10 亿美元,用于继续推出新产品,同时扩大产能以满足对现有器件的需求。

“2022年第二季度新产品预告"
2022年第二季度新产品预告

ADCC 代表“ADC 计算”, 它是模拟和数字功能的混合体。片上模拟功能(包括 8 位、10 位和 12 位 ADC)可以使用图形工具轻松配置。其他选项包括具有相关可编程增益放大器(PGA)的 ADC,从而无需使用外部 PGA,以及具有上下文/排序功能的 ADC。其他功能包括片上比较器、数模转换器(DAC)、斜坡发生器、温度传感器、电压基准、过零检测和运算放大器(运放)。

考虑下面介绍的运算放大器示例。传统方法是使用外部运算放大器(左)。片上运算放大器(右)的优势包括节省电路板上的空间、减少物料清单(BOM)以及能够在程序控制下动态更改软件中的增益和其他特性(如果您要测量多个信号,每个信号都需要不同的运算放大器参数,这很有用)。

“带有内部运算放大器的
带有内部运算放大器的 PIC®和AVR®单片机

独立于内核的外设(CIP)背后的概念是,外设可以在内核处于“打盹”模式或处理更重要的任务时自行执行任务。例如,CIP 可以在内核进入休眠状态时从传感器获取读数,然后对结果进行累积、求平均值和/或过滤。稍后,当内核唤醒时,外设可以准备好其预处理的数据并等待着。

“使用独立于内核的外设创建自定义外设"
使用独立于内核的外设创建自定义外设

当 CIP 组合在一起创建自定义外设或“超级外设”时,事情开始变得非常有趣。一个很好的例子如下所示。这涉及希望使用串行总线通信协议控制一堆 LED 的应用。

“将
将 CIP 组合在一起以创建“超级外设”或“超级模块”

指定“哪个 LED”和“什么颜色”涉及一个相当复杂的信号,并且可能需要发送大量数据。这通常需要一个高速 32 位 MCU。然而,通过使用少数 CIP 外设——定时器、SPI、PWM 和一些使用 CLC(可配置逻辑单元)实现的逻辑——可以在 8 位 PIC 单片机上实现该算法。(与 PIC MCU的 CLC 不同,可以使用可配置自定义逻辑(CCL)在 AVR 上实现相同的功能。)

结果是允许 8 位 MCU 以比指令速度(即在内核上运行的指令)快得多的逻辑速度驱动一串 LED,同时释放内核以执行其他任务。

一般来说,拥有 CIP,特别是能够将它们组合在一起,打开了通往各种部署场景的大门,允许外设处理各种传感器数据。

“常见的传感器输出类型"
常见的传感器输出类型

考虑下面所示的示例,其中使用 8 位 PIC 或 AVR 单片机来监控温度、湿度和振动传感器的输出。可能来自温度传感器的信号比来自湿度传感器的信号需要更高的增益,这可以通过在程序控制下来回交换片上运算放大器的增益来实现。

“典型的多传感器应用"
典型的多传感器应用

同时,MCU 可能以 5V 运行,而使用 I2C 通信的振动传感器仅需要 1.8V。在这种情况下,解决方案不是采用外部电压电平转换器,而是采用 MCU 的多电压输入/输出(MVIO)功能。

上面的示例显示了 MVIO 和 I2C 的组合,但 MVIO 也可以与通用输入/输出(GPIO)一起使用。事实上,这引出了另一个例子,因为运行在 5V 的 8 位 PIC 或 AVR MCU 可用于从传感器读取值,从而实现比 3.3V MCU 更好的分辨率,而 PIC/ AVR MCU可以使用其 MVIO 功能将此数据传送到 3.3V 32 位 PIC32 SAM MCU。

让 PIC/AVR MCU的新手感到困惑的一件事是可用的不同组件数量之多,每个组件都有不同数量的引脚以及不同的功能和外设组合。有几种方法可以解决这个问题。就我而言,我会直接问我的朋友 Joe Farr。关于Microchip PIC 和 AVR MCU,他就是一本行走着的百科全书。对于那些不认识 Joe 的人,Microchip 网站上有一个产品选型指南,用户说了“我需要这个功能”后,就会被引导到合适的产品。或者,用户可以说“我想实现这个应用”,该工具不仅可以将他们引导到合适的产品,还可以引导到相关的固件和软件以及开发工具。

Greg 在结束谈话前,说了一些很有趣的内容。那就是不光是 8 位 MCU这块饼在增长,各种新的应用也不断涌现,就像有了一个全新的饼。因此,他表示:“Microchip 非常看好 8 位 MCU 市场。”这对我来说是个好消息,因为我喜欢 8 位 MCU。那么你呢?你有什么想法愿意分享吗?

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

围观 101

安全威胁日益复杂,给物联网(IoT)、消费、工业、医疗和其他市场产品开发带来了挑战。这些产品必须具备强大的嵌入式安全性,同时还要求低功耗以延长电池寿命。Microchip Technology Inc.(美国微芯科技公司)近日宣布推出业界首款在单一封装中集成了安全子系统和Arm® TrustZone®技术的PIC32CM LS60单片机(MCU)。新款单片机集成了Microchip的可信平台(Trust Platform)安全子系统,让使用单个单片机而不是两个或多个芯片来开发终端产品变得更加容易。现在,设计人员可使用这款值得信赖的32位单片机,来保护产品和终端用户的智能家居设备、智能手机或平板电脑配件、便携式医疗设备、可穿戴设备、互联电器和工业机器人免受远程或物理攻击。

“Microchip发布业界首款集成强大安全子系统和Arm®

随着物联网行业的持续快速发展,对于边缘设备而言,高标准的安全保护已变得不可或缺。PIC32CM LS60结合了易于使用的Arm TrustZone技术和通用标准联合解释库(JIL)中认定的“高”等级可信平台安全子系统,使开发人员能够实施业界公认的安全实践和对策,以防范各类已知的远程和物理攻击。相关设计得到了MPLAB® 代码配置器(MCC) TrustZone Manager和可信平台设计套件等工具的支持,从而简化了安全子系统的配置。Microchip 可信平台配置服务可用于安全地配置密钥和证书。

Microchip 32位单片机业务部副总裁Rod Drake表示:“PIC32CM LS60在单个封装中集成了Arm TrustZone技术和Microchip的安全子系统,是市场上前所未有的产品。我们相信这款单片机的安全性、易用性和低功耗将有力地推动物联网应用采用先进的安全技术。”

随着防水可穿戴设备和现代电器越来越多地采用触屏功能,嵌入式设计人员面临着开发能在嘈杂和潮湿环境中稳健运行的触屏界面的挑战。PIC32CM LS60集成了增强型外设触屏控制器,具有Driven Shield Plus功能,可防止因潮湿造成的误触屏,并提供高抗噪能力,以实现卓越的触屏界面功能。

此外,该器件具有独立于内核的SleepWalking外设和事件系统。这些外设可使单片机内核长时间处于休眠模式,以减少功耗。它还配有片上模拟,包括运算放大器(o运放)、数模转换器(DAC)和模数转换器(ADC),可在休眠模式下运行并与各种传感器连接。PIC32CM LS60与MPLAB Data Visualizer和Power Debugger工具兼容,可用于实时监测、分析和微调功耗数据。这使客户更容易开发低功耗应用,并更快地向市场推出电池续航时间更长的产品。

开发工具

Microchip提供以下开发工具和服务来支持PIC32CM LS60及其他型号:可信平台配置服务、可信平台设计套件(TPDS)、带有用于Arm TrustZone的MPLAB 代码配置器的MPLAB Harmony v3平台、触摸函数库、触摸配置器、MPLAB Data Visualizer、功率调试器,以及PIC32CM LE00 Curiosity Pro评估工具包、PIC32CM LS00 Curiosity Pro评估工具包、PIC32CM LS60 Curiosity Pro评估工具包、PIC32CM LE00超低功耗防水触屏参考设计、MPLAB X集成开发环境(IDE)及其调试器、编程器和编译器生态系统。

供货

除PIC32CM5164LS60安全性型号外,PIC32CM LE00通用型号和PIC32CM LS00 Arm TrustZone技术型号(无安全子系统)也可提供。PIC32CM5164LS60、PIC32CM5164LS00和 PIC32CM5164LE00现已开始供货,100引脚TQFP封装,10,000件起订,单件售价分别为5.48美元、4.33美元和4.18美元。如需了解更多信息或购买,请联系Microchip销售代表或访问Microchip直销网站:www.microchipDIRECT.com

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

围观 24

在单片机编程过程中,经常会使用到中断。那么,什么是单片机中断,它与CPU的轮询有什么区别?在本文中,单片机开发工程师将对单片机中断和CPU轮询做个简单的介绍。

“单片机中断与CPU的轮询有什么区别"

中断

中断是一种硬件机制,在这种机制中,设备会通知CPU它需要引起注意。中断可以随时发生。因此,当CPU通过指示中断请求线收到中断信号时,CPU停止当前进程并通过将控制权传递给服务设备的中断处理程序来响应该中断。

轮询

轮询不是一种硬件机制,它是一种协议,CPU会稳定地检查该设备是否需要注意。无论设备告诉处理单元它希望进行硬件处理的位置如何,在轮询过程中,处理单元都会不断询问I/O设备是否希望进行CPU处理。CPU不断检查连接到其上的每个设备,以侦查是否有任何设备需要硬件注意。

每个设备都有一个指示命令就绪的位,指示该设备的状态,即该命令是否被硬件终止。如果命令位已准备就绪,则该命令已失效;否则,如果该位为零,则该命令无效。

让我们看看中断和轮询之间的区别:

  • 在中断时,设备会通知CPU它需要引起注意。而在轮询中,CPU会稳定地检查设备是否需要注意。
  • 中断不是协议,而是一种硬件机制。轮询不是硬件机制,而是协议。
  • 在中断中,该设备由中断处理程序提供服务。轮询时,该设备由CPU维修。
  • 断可以随时发生。轮询时,CPU会以固定或适当的间隔稳定地对设备进行投票。
  • 在中断中,中断请求线用作指示设备需要维修的指示。在轮询时,命令就绪位用作指示,表明设备需要维修。
  • 在中断中,一旦任何设备将其中断,处理器就会受到干扰。相反,在轮询中,处理器通过重复检查每个设备的命令就绪位来浪费无数的处理器周期。

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

围观 170

如今,运行实时操作系统(RTOS)的大型32位单片机(MCU)和微处理器(MPU)日益普及。不过,如果使用一个大型单片机处理复杂的应用,可能会在执行小型后台处理任务时遇到CPU资源方面的问题,这些任务虽然并不复杂,但十分耗时。8位和16位MCU等小型器件可用于减轻32位器件的工作负荷。

试想一下这样一个示例:将一个32位MCU用于控制汽车的非安全功能,如娱乐系统、环境照明和空调。此32位器件必须对其资源进行分配,以便处理与这些功能相关的所有任务。这样的任务还包括测量驾驶室内多个点的温度、打开/关闭空调系统、更新图形显示、处理用户输入、调整照明条件和播放音乐。即使对于大型32位器件,这些工作量也过于繁重。

但是,如果32位器件将部分任务负荷转移给几乎不需要监控的子处理器,每个子处理器仅负责处理其中的1或2个任务,那么这些任务会更易于管理。这可以释放主处理器上的CPU资源,从而降低软件的复杂性,同时提高性能并缩短执行时间。

这种解决方案与单片机中的外设有异曲同工之妙。外设是专用硬件的小型模块,可以添加新功能(例如运算放大器或模数转换器),也可以减少执行给定功能时CPU必须承担的工作量。在某些情况下,初始化后,外设可独立于CPU运行。

为了说明外设的优势,我们以产生脉宽调制(PWM)信号为例。要在没有专用外设的情况下产生PWM,只需将I/O线设为高电平,等待一定数量的周期后,将其设为低电平,再等待一段时间,然后重复操作。这会占用大量CPU周期,并且对于某些功能(如RTOS)来说,难以可靠地执行。相比之下,PWM外设允许CPU在执行其他任务的同时设置所需的波形参数。

今天推荐专家技术文章《部署处理特定任务的单片机来简化复杂设计》将介绍两个示例。第一个示例说明了减轻CPU密集型任务负荷的优势。在该案例中,使用了一个8位MCU来创建I/O扩展器。I/O扩展器并不复杂;然而,由于需要频繁处理中断,因此它们会占用大量的CPU时间。通过使用专用MCU来完成这项任务,大型32位器件可以减少I/O使用和需要处理的中断次数。此外,I/O扩展器的功能集可在软件中设置,因此支持针对应用进行定制和调整。

第二个示例以创建独立于CPU运行的电压频率(V/F)转换器为例,展示了独立于内核的外设的性能。在这个示例中,CPU的唯一功能是初始化外设并将调试打印消息发送到UART。在大型系统中,当V/F在后台运行时,CPU可以执行另一个简单的任务。

详阅请点击下载《部署处理特定任务的单片机来简化复杂设计》

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

围观 30

HMI(Human Machine Interface,人机接口)技术的发展要求产品更加设计精良和操作方便,以提高附加价值。因此,对于电容式触控传感器的需求越来越多,这种电容式触控传感器不仅需要能够根据外壳设计理念灵活采用木材或透明亚克力等各种材料作为操作面板,还需要能够通过LED显示屏引导用户操作等来实现良好的易用性。然而,有些用户即便想要引入电容式触控传感器,也难免会在着手评测时感到束手无措。

为此,瑞萨为RX系列单片机配套了Renesas Solution Starter Kit和Renesas Starter Kit等主板,以便广大用户能够快速评测电容式触控传感器。在本期文章中,我将为大家介绍一下如何使用最廉价和最基本的目标板,以简单的方式对电容式触控传感器进行初步评测。

目标板可以访问单片机的所有信号引脚且售价仅为3,000日元,简直是用于早期决策的最佳评测主板。传统目标板的规格无法安装触控传感器工作所需的LPF电容,因此很难对其进行评测,但是安装有最新RX140单片机的RX140目标板提供了用于连接LPF电容的切割图案,并做了一些改进,以方便进行触控传感器初步评测。

点击查看RX140 MCU的更多信息

点击查看RX140目标板的更多信息

首先,按照本主板线路图和用户手册中的说明,拆下与RX140单片机TSCAP端子连接的GPIO用0Ω电阻,安装触控传感器用电容和0Ω电阻。然后将排针安装到主板的通孔上,连接触控传感器用电极。有关电极制作方法,请参阅应用指南“*电容式触控电极设计指南”。

“最新型32位单片机RX140帮您轻松实现电容式触控传感器的初步评测"

*关于电容式触控电极设计指南的更多信息,请访问:

https://www2.renesas.cn/us/zh/document/apn/capacitive-sensor-microcontrollers-ctsu-capacitive-touch-electrode-design-guide

准备好主板后,启动瑞萨提供的集成开发环境e2 studio,创建新项目。项目创建时,选中“Use Smart Configurator”,即可轻松地配置单片机的时钟、端子、周边功能和下载驱动程序。此外,将电容式触控传感器开发辅助工具“*QE for Capacitive Touch”作为插件添加到项目中,即可在GUI中轻松地进行触控检测程序自动生成、测量值监测和参数调整等操作。有关使用电容式触控传感器编写程序的详细信息,请参阅应用指南“*使用QE和FIT进行电容式触控应用的开发”。

*关于QE for Capacitive Touch的更多信息,请访问:

https://www2.renesas.cn/cn/zh/software-tool/qe-capacitive-touch-development-assistance-tool-capacitive-touch-sensors

*关于使用QE和FIT进行电容式触控应用的开发的更多信息,请访问:

https://www2.renesas.cn/cn/zh/document/apn/rx-family-using-qe-and-fit-develop-capacitive-touch-applications-rev100

将程序写入RX140单片机后,开始调试时,可以通过QE for Capacitive Touch的监视窗口,实时直观地查看触控检测的状态。

“最新型32位单片机RX140帮您轻松实现电容式触控传感器的初步评测"

“最新型32位单片机RX140帮您轻松实现电容式触控传感器的初步评测"

瑞萨提供有丰富的软件和功能强大且易于使用的开发工具,助力用户开发工作。利用这些功能,任何人员都可以通过Target Board for RX140轻松地对电容式触控传感器进行评测。心动不如行动,快来一试吧!

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

围观 28

在2022年,随着智能手机、自动驾驶汽车和5G无线连接主导嵌入式设计市场,Microchip的8位PIC®和AVR®单片机(MCU)系列市场份额不断扩大。在过去50年里,8位MCU市场一直在稳步增长,Microchip每年的销量相当于西半球人手一件。为了支持持续的增长趋势,Microchip Technology Inc.(美国微芯科技公司)近日宣布推出5个新产品系列和60多款新独立器件,为嵌入式设计人员提供最常见问题的简单解决方案。

“Microchip发布多款应用于当今主流嵌入式设计的PIC®和AVR®单片机产品"

寻求创新设计的设计人员正转向利用Microchip的PIC和AVR单片机系列新产品。这些新产品拥有强大的处理能力,能够与其他芯片和模拟外设轻松通信,在构建时无需对印刷电路板(PCB)进行改动,就能实现超强配置。这些器件将类似ASIC的功能与简单的开发经验相结合,扩展了传统MCU的功能,并允许它们被配置为智能外设芯片。类似PIC16F171系列中的软件控制运算放大器、多电压输入/输出(MVIO)和带计算功能的模数转换器(ADCC)的智能外设,为原本不使用传统MCU的应用带来了新的价值。

使用不同电源电压芯片的系统经常需要跨越多个电压域(例如,将5V的 MCU连接到1.8V的传感器)。此类系统通常需要电平转换硬件,从而增加了成本。Microchip最新的8位MCU(包括AVR DD系列)中的MVIO外设允许MCU上的单个端口在与MCU其他部分不同的电压域中工作,从而无需额外的外部元件。

有些系统要求一定水平的速度和响应时间,这是基于软件的处理难以达到的。Microchip PIC和AVR产品系列的独立于内核的外设(CIP)可以用MPLAB®代码配置器(MCC)进行编程,以方便连接形成硬件处理链。这使得创建定制外设成为可能,从而消除了软件处理的周期时间。例如,通过配置一个由脉宽调制器(PWM)、SPI接口和可配置逻辑单元(CLC)组成的超级外设,即可轻松控制一个需要独特时序才能正确驱动的WS2812 LED阵列。

随着8位PIC和AVR MCU器件市场的持续增长,Microchip通过坚持其产品组合和支持结构中的强大基本功能,持续响应客户的长期需求。PIC和AVR MCU非常容易用于设计,其支持网络使Microchip的客户能缩短实现收益的时间。8位MCU产品组合是引脚(pin-to-pin)兼容的,当需要更高性能或客户希望最大限度地提高产品供货,同时尽量减少重新设计的要求时,可以选择替代的PIC或AVR MCU。

Microchip 8位单片机业务部营销副总裁Greg Robinson表示:“PIC和AVR MCU非常受欢迎,它们的设计能够满足我们客户对当前以及未来应用的要求。我们还为8位PIC和AVR MCU建立了强大的供应链,绝大部分都在Microchip自有工厂中生产。这使我们能够以业内不常有的方式控制生产过程。”

开发工具

Microchip提供由硬件和软件工具组成的完整开发生态系统,包括MPLAB® X和MPLAB® Xpress集成开发环境(IDE)以及MPLAB®代码配置器(MCC),后者提供直观的图形界面,为基于8位MCU的项目生成生产就绪的安装和应用代码。

供货

所有5个产品系列目前都已提供样片,如需了解更多信息,请点击此处

Microchip Technology Inc. 简介

Microchip Technology Inc.是致力于智能、互联和安全的嵌入式控制解决方案的领先供应商。 其易于使用的开发工具和丰富的产品组合让客户能够创建最佳设计,从而在降低风险的同时减少系统总成本,缩短上市时间。Microchip的解决方案为工业、汽车、消费、航天和国防、通信以及计算市场中12万多家客户提供服务。Microchip总部位于美国亚利桑那州Chandler市,提供出色的技术支持、可靠的产品交付和卓越的质量。详情请访问公司网站www.microchip.com

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

围观 37

摘 要

本文介绍了RA6M1单片机在电动汽车交流充电桩的应用及快速开发过程。

电动汽车交流充电桩

交流充电桩俗称“慢充”,交流单相充电桩(一般最大额定功率为7kW),充电桩一般与交流电网(市电)连接。交流充电桩主要适用于为小型纯电动汽车或可插电混合动力电动汽车充电,为电动汽车车载充电机提供交流电源的供电装置,相当于只是起了一个控制电源的作用。

根据不同车辆电池容量,车辆充满电的时间一般需要3至8个小时。根据交流充电桩系统实际需求,一般会搭配两颗ARM Cortex M4内核以上的MCU,其中一颗为主要核心MCU,用于整桩控制,包含充电控制、电能计量、计费单元控制和通信传输;另一颗MCU用于在无网络状态使用,可搭配射频卡或Wi-Fi使用,一般应用于个体使用或企业内部使用。

整体交流充电桩使用的外设及资源包含:GPIO、ADC、PWM、IIC、UART和USB等资源。Renesas RA6M1 MCU,性能非常适合本设计的要求。

RA6M1

  • 100Pin的QFP封装

  • ARM Cortex M4内核的MCU带有DSP等功能

  • 丰富的GPIO和外设资源;

  • 120MZH的主频

  • 带有512kB Flash和256kB SRAM,可以减少片外FLASH的需求,可以将关键数据存储在内部Data Flash中。

交流充电桩的设计框图如图1及部分硬件原理图如图2所示:

“图1
图1 交流充电桩原理图

模块功能介绍

  • GPIO和光耦控制继电器的开合

  • PWM监测汽车的CP信号

  • ADC采集高压信号

  • UART用于射频非接卡和LCD等通讯

  • 温湿度监测和4G模组

  • Data Flash 使用

  • PWM监测电动汽车的CP信号模块介绍

交流充电桩的CP信号是用于监控电动汽车和充电桩交互的功能的信号,它是由MCU发出的PWM信号。CP信号的幅值范围是±12V,PWM信号的占空比表示当前充电桩为电动汽车提供的最大充电电流数据,当PWM为1kHz,53%占空比的时候,可以为电动汽车提供32A的充电电流。

● UART用于射频非接卡和LCD等通讯模块介绍

LCD选用迪文的触摸液晶屏,主要用于人机界面显示和急停按钮反馈,LCD屏幕输出充电桩当前的信息,包含输出电压、电流、充电量和费用清单等。

射频非接卡是预留的交互接口,为交流充电桩可配置选型,当交流充电桩的终端用户为个体或企业内部使用时候,无需计费单元和联网功能,可使用射频非接卡可以进行自助充电,完全可以脱离网络对电动汽车进行充电。

● GPIO和光耦控制继电器的开合

由于整个系统采用交流220V供电,为了提高系统的稳定性GPIO的输出控制全部带有光耦,同时使用MOS和继电器控制电源的通断。

● 温湿度监测和4G模组

板级温湿度监测, 主要用于监测PCB的板载温度,由于整板采用交流220V电源供电,同时后续电路有多颗LDO,使用温湿度传感器监测整板温度异常和安装环境的湿度异常,当发生异常后MCU将关闭充电功能,保证系统的稳定性和安全性。

● Data Flash

Data Flash主要用于记录在断网状态下充电桩的结算数据和异常数据记录,保证客户在使用过程中即便发生无网络连接状态客户的充电数据信息都可以记录。

“图2
图2 交流充电桩部分原理图

在硬件设计完成后,开始进行软件程序编写,Renesas IDE是e2 studio,调试器是E2-lite,官方文档很详细,基本上熟悉一天的话,底层的驱动及应用就可以上手了,同时Renesas给出了很多例程都可以快速的导入到IDE里面,在新建工程时建议将编译工具链选择最新版本,不仅编译速度快而且电脑不卡。在不到60天的时间内,我完成了样机的Demo调试,性能完全满足要求。

在使用过Renesas的MCU后,感觉Renesas基于ARM Cortex M内核的MCU在功能和IDE方面非常好用,无论在硬件软件上Renesas MCU都是值得选择的单片机,从此开始了我的Renesas MCU开发之路。

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

围观 291

页面

订阅 RSS - 单片机