2016-09-13 16:19:14 jdh99 阅读数 4414

设计单片机日志系统


本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.

 

环境:

主机:WIN10

开发环境:MDK5.12

MCU:STM32F407


说明:
为单片机设计了一套简单的日志系统,通过日志系统提供的接口可以查看设备状态,并进行一些基本的调试。
日志系统通过串口输出,所以单片机需要准备一个串口供日志系统使用。注意串口发送不能用DMA发送(避免在在中断中打印日志造成的中断竞争),接收可以用DMA接收。

功能:
  • 打开/关闭各个模块的调试输出
  • 输入动作指令,让设备进行一些动作
  • 打印系统运行日志
指令:
  • H:帮助
  • O:调试输出全开
  • O1:打开1号模块,打开其他模块指令类似
  • F:调试输出全关
  • F1:关闭1号模块
  • I:输出系统日志
  • C:清除系统日志
  • A1:执行1号动作,执行其他动作指令类似

源代码:

log.h:

/**
* Copyright (c), 2015-2025
* @file log.h
* @brief 日志模块主文件
* @author jdh
* @date 2015/5/7
* @update 2015/6/19
* @update 2015/6/23
* @update 2015/6/30
* @update 2015/7/8
* @update 2015/7/13
* @update 2015/8/12
* @update 2015/8/18
* @update 2016/5/17
* @update 2016/6/30
* @update 2016/7/22
* @update 2016/8/11
* @update 2016/8/24
* @update 2016/9/2
* @update 2016/9/5
* @update 2016/9/7
* @update 2016/9/9
*/

#ifndef _LOG_H_
#define _LOG_H_

/*********************************************************************
*							头文件
**********************************************************************/

#include "world.h"
#include "console.h"

/*********************************************************************
*							宏定义
**********************************************************************/

/**
* @brief 日志模块数量
*/
#define NUM_LOG					5

/**
* @brief 模块编号
*/

#define LOG_TEST				0
#define LOG_CLOCK				1
#define LOG_DW1000				2
#define LOG_DW1000_STATUS		3
#define LOG_DEAL_BUS			4

/*********************************************************************
*							数据结构
**********************************************************************/

/**
* @brief 日志
*/

struct _Log
{
	//公有日志
	//收到移动点数据次数
	uint32_t num_rf_rx;
	//发送超时被删除点数
	uint32_t num_time_out_delete;
	//RF发送次数
	uint32_t num_rf_tx;
	//RF校时或分配事件次数
	uint32_t num_rf_time;
	//RF随机信道发送次数
	uint32_t num_rf_random_tx;
	//复位次数
	uint32_t num_reset;
	//运行时间,分度为0.5s
	uint32_t time_run;
	//收到同步脉冲计数
	uint32_t num_sync_pulse;
	//收到422轮询/事件帧次数
	uint32_t num_bus_poll;
	//收到422事务命令次数
	uint32_t num_bus_down_cmd;
	//收到422事务命令中事件个数
	uint32_t num_bus_down_cmd_dot;
	//收到有效的422帧次数
	uint32_t num_valid_bus;
	//收到无效的422帧次数
	uint32_t num_invalid_bus;
	//接收时间错误
	uint32_t num_time_error;
	
	//私有日志
	//dw1000芯片错误次数
	uint32_t num_dw1000_error[NUM_DW1000];
	//接收时间错误
	uint32_t num_dw1000_time_error[NUM_DW1000];
	//轮询超时被删除点数
	uint32_t num_poll_time_out_delete;
	//接收超时复位
	uint32_t num_dw1000_time_out_reset[NUM_DW1000];
	//dw1000芯片状态错误次数
	uint32_t num_dw1000_status_error[NUM_DW1000];
};

/*********************************************************************
*							函数
**********************************************************************/

/**
* @brief 模块加载
*/

void log_load(void);

/**
* @brief 读取日志
* @retval 日志
*/

struct _Log log_read(void);

/**
* @brief 清除日志
*/

void log_clear(void);

/**
* @brief 收到移动点数据次数
*/

void log_write_num_rf_rx(void);

/**
* @brief 发送超时被删除点数
*/

void log_write_num_time_out_delete(void);

/**
* @brief RF发送次数
*/

void log_write_num_rf_tx(void);

/**
* @brief RF校时或分配事件次数
*/

void log_write_num_rf_time(void);

/**
* @brief RF随机信道发送次数
*/

void log_write_num_rf_random_tx(void);

/**
* @brief 复位次数
*/

void log_write_num_reset(void);

/**
* @brief 运行时间
* @param add_time:增加的时间.单位:0.5s
*/

void log_write_time_run(uint32_t add_time);

/**
* @brief 收到同步脉冲计数
*/

void log_write_num_sync_pulse(void);

/**
* @brief 收到422轮询/事件帧次数
*/

void log_write_num_bus_poll(void);

/**
* @brief 收到422事务命令次数
*/

void log_write_num_bus_down_cmd(void);

/**
* @brief 收到422事务命令中事件个数
*/

void log_write_num_bus_down_cmd_dot(void);

/**
* @brief 收到有效的422帧次数
*/

void log_write_num_valid_bus(void);

/**
* @brief 收到无效的422帧次数
*/

void log_write_num_invalid_bus(void);

/**
* @brief 收到时间错误
*/

void log_write_num_time_error(void);

/**
* @brief dw1000芯片错误次数
* @param index:模块序号,从0开始
*/

void log_write_num_dw1000_error(uint8_t index);

/**
* @brief dw1000芯片接收时间错误次数
* @param index:模块序号,从0开始
*/

void log_write_num_dw1000_time_error(uint8_t index);

/**
* @brief 轮询超时被删除点数
*/

void log_write_num_poll_time_out_delete(void);

/**
* @brief dw1000芯片接收超时复位次数
* @param index:模块序号,从0开始
*/

void log_write_num_dw1000_time_out_reset(uint8_t index);

/**
* @brief dw1000芯片状态错误次数
* @param index:模块序号,从0开始
*/

void log_write_num_dw1000_status_error(uint8_t index);

/**
* @brief 控制台打印
* @param index:模块编号
* @param info:打印的信息
*/

void log_print(uint8_t index,char *info);

/**
* @brief 控制台强制打印
* @param info:打印的信息
*/

void log_print_force(char *info);

/**
* @brief 接收处理
* @param rx:接收数据
*/

void log_deal_rx(struct _Console_Rx rx);

#endif

log.c:

/**
* Copyright (c), 2015-2025
* @file log.c
* @brief 日志模块主文件
* @author jdh
* @email jdh821@163.com
* @date 2015/5/7
* @update 2015/6/19
* @update 2015/6/30
* @update 2015/7/8
* @update 2015/7/13
* @update 2015/7/15
* @update 2015/8/12
* @update 2015/8/13
* @update 2015/11/11
* @update 2016/5/17
* @update 2016/6/30
* @update 2016/7/22
* @update 2016/8/11
* @update 2016/8/18
* @update 2016/8/22
* @update 2016/8/24
* @update 2016/9/2
* @update 2016/9/5
* @update 2016/9/7
* @update 2016/9/9
* @update 2016/9/12
*/

/*********************************************************************
*							头文件
**********************************************************************/

#include "log.h"
#include "protocol_bus.h"
#include "protocol_uwb.h"
#include "para_manage.h"

/*********************************************************************
*							静态变量
**********************************************************************/

/**
* @brief 运行日志
*/

static struct _Log Log __attribute__((section("NO_INIT"),zero_init));

/**
* @brief 日志过滤标志数组,0:未过滤,1:过滤
*/

static uint8_t Filter[NUM_LOG] = {1, 1, 1, 1, 1};

/**
* @brief 暂停输出标志,0:未暂停输出,1:暂停输出
*/

static uint8_t Flag_Pause = 0;

/*********************************************************************
*							静态函数
**********************************************************************/

/**
* @brief 帮助界面
*/

static void help(void);

/**
* @brief 输出本地日志
*/

static void print_log(void);

/**
* @brief 处理动作
* @param index:动作编号
*/

static void deal_action(uint8_t index);

/*********************************************************************
*							函数
**********************************************************************/

/**
* @brief 模块加载
*/

void log_load(void)
{
	//检查是否上电
	if (RCC_GetFlagStatus(RCC_FLAG_PORRST) == SET)
	{
		//清除标志位
		RCC_ClearFlag();
		//清除日志
		memset(&Log, 0, sizeof(Log));
	}
	else
	{
	 	//日志:复位次数
		Log.num_reset++;
	}
}

/**
* @brief 清除日志
*/

void log_clear(void)
{
	memset(&Log, 0, sizeof(Log));
}

/**
* @brief 读取日志
* @retval 日志
*/

struct _Log log_read(void)
{	
	return Log;
}

/**
* @brief 收到移动点数据次数
*/

void log_write_num_rf_rx(void)
{
	Log.num_rf_rx++;
}

/**
* @brief 发送超时被删除点数
*/

void log_write_num_time_out_delete(void)
{
	Log.num_time_out_delete++;
}

/**
* @brief RF发送次数
*/

void log_write_num_rf_tx(void)
{
	Log.num_rf_tx++;
}

/**
* @brief RF校时或分配事件次数
*/

void log_write_num_rf_time(void)
{
	Log.num_rf_time++;
}

/**
* @brief RF随机信道发送次数
*/

void log_write_num_rf_random_tx(void)
{
	Log.num_rf_random_tx++;
}

/**
* @brief 复位次数
*/

void log_write_num_reset(void)
{
	Log.num_reset++;
}

/**
* @brief 运行时间
* @param add_time:增加的时间.单位:0.5s
*/

void log_write_time_run(uint32_t add_time)
{
	Log.time_run += add_time;
}

/**
* @brief 收到同步脉冲计数
*/

void log_write_num_sync_pulse(void)
{
	Log.num_sync_pulse++;
}

/**
* @brief 收到422轮询/事件帧次数
*/

void log_write_num_bus_poll(void)
{
	Log.num_bus_poll++;
}

/**
* @brief 收到422事务命令次数
*/

void log_write_num_bus_down_cmd(void)
{
	Log.num_bus_down_cmd++;
}

/**
* @brief 收到422事务命令中事件个数
*/

void log_write_num_bus_down_cmd_dot(void)
{
	Log.num_bus_down_cmd_dot++;
}

/**
* @brief 收到有效的422帧次数
*/

void log_write_num_valid_bus(void)
{
	Log.num_valid_bus++;
}

/**
* @brief 收到无效的422帧次数
*/

void log_write_num_invalid_bus(void)
{
	Log.num_invalid_bus++;
}

/**
* @brief 收到时间错误
*/

void log_write_num_time_error(void)
{
	Log.num_time_error++;
}

/**
* @brief dw1000芯片错误次数
* @param index:模块序号,从0开始
*/

void log_write_num_dw1000_error(uint8_t index)
{
	Log.num_dw1000_error[index]++;
}

/**
* @brief dw1000芯片接收时间错误次数
* @param index:模块序号,从0开始
*/

void log_write_num_dw1000_time_error(uint8_t index)
{
	Log.num_dw1000_time_error[index]++;
}

/**
* @brief 轮询超时被删除点数
*/

void log_write_num_poll_time_out_delete(void)
{
	Log.num_poll_time_out_delete++;
}

/**
* @brief dw1000芯片接收超时复位次数
* @param index:模块序号,从0开始
*/

void log_write_num_dw1000_time_out_reset(uint8_t index)
{
	Log.num_dw1000_time_out_reset[index]++;
}

/**
* @brief dw1000芯片状态错误次数
* @param index:模块序号,从0开始
*/

void log_write_num_dw1000_status_error(uint8_t index)
{
	Log.num_dw1000_status_error[index]++;
}

/**
* @brief 控制台打印
* @param index:模块编号
* @param info:打印的信息
*/

void log_print(uint8_t index,char *info)
{
	T_Time time;
	char log_out[256] = {0};
	
	//判断是否是暂停输出
	if (Flag_Pause)
	{
		return;
	}
	
	//判断是否被过滤输出
	if (Filter[index])
	{
		return;
	}
	
	time = get_time();
	sprintf(log_out,"%05d:%03d:%03d %s\r\n",time.s,time.ms,time.us,info);
	console_tx((uint8_t *)log_out,strlen(log_out));
}

/**
* @brief 控制台强制打印
* @param info:打印的信息
*/

void log_print_force(char *info)
{
	T_Time time;
	char log_out[256] = {0};
	
	time = get_time();
	sprintf(log_out,"%05d:%03d:%03d %s\r\n",time.s,time.ms,time.us,info);
	console_tx((uint8_t *)log_out,strlen(log_out));
}

/**
* @brief 接收处理
* @param rx:接收数据
*/

void log_deal_rx(struct _Console_Rx rx)
{
	uint8_t i = 0;
	int num = 0;
	char str_temp[5] = {0};
	
	//判断是否是输出本地日志
	if (rx.len == 1 && rx.buf[0] == 'I')
	{
		print_log();
		return;
	}
	
	//判断是否是输出本地日志
	if (rx.len == 1 && rx.buf[0] == 'C')
	{
		log_clear();
		return;
	}
	
	//判断是否是暂停输出
	if (rx.len == 1 && rx.buf[0] == 'P')
	{
		Flag_Pause = 1;
		return;
	}
	
	//判断是否是打开输出
	if (rx.len == 1 && rx.buf[0] == 'S')
	{
		Flag_Pause = 0;
		return;
	}
	
	//判断是否是帮助
	if (rx.len == 1 && rx.buf[0] == 'H')
	{
		help();
		return;
	}
	
	//判断是否是过滤规则
	if (rx.len <= 3 && rx.buf[0] == 'F')
	{	
		if (rx.len == 1)
		{
			//全部过滤
			for (i = 0;i < NUM_LOG;i++)
			{
				Filter[i] = 1;
			}
			return;
		}
		
		memset(str_temp,sizeof(str_temp),0);
		memcpy(str_temp,rx.buf,rx.len);
		sscanf(str_temp,"F%d",&num);
		Filter[num] = 1;
		return;
	}
	
	//判断是否是打开模块
	if (rx.len <= 3 && rx.buf[0] == 'O')
	{	
		if (rx.len == 1)
		{
			//清除过滤规则
			for (i = 0;i < NUM_LOG;i++)
			{
				Filter[i] = 0;
			}
			return;
		}
		
		memset(str_temp,sizeof(str_temp),0);
		memcpy(str_temp,rx.buf,rx.len);
		sscanf(str_temp,"O%d",&num);
		Filter[num] = 0;
		return;
	}
	
	//判断是否是打开模块
	if (rx.len > 1 && rx.len <= 3 && rx.buf[0] == 'A')
	{	
		memset(str_temp,sizeof(str_temp),0);
		memcpy(str_temp,rx.buf,rx.len);
		sscanf(str_temp,"A%d",&num);
		deal_action(num);
		return;
	}
}

/**
* @brief 帮助界面
*/

static void help(void)
{
	char log_out[100] = {0};
	
	strcpy(log_out,"*******************************************\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"             UWB基站日志帮助界面            \r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"硬件版本:%d 软件版本:%d\r\n",VERSION_HARD,VERSION_SOFT);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"总线通信协议版本:%s\r\n",VERSION_NAME_BUS);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"空口通信协议版本:%s\r\n",VERSION_NAME_UWB);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"CSSN:0x%06x ID:0x%04x\r\n",para_manage_read_cssn(), para_manage_read_id());
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷键I(INFO)输出本地日志\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷键C(CLEAR)清除本地日志\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷键P(PAUSE)暂停输出\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷键S(START)开始输出\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷键A(ACTION)动作\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"A1:读取1号dw1000状态寄存器\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"A2:清除1号dw1000状态寄存器\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"A3:打开1号dw1000接收\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷键H(HELP)打开帮助\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷键F(FILTER)过滤输出\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"例:过滤1号模块:F1\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"例:全部过滤:F\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"快捷键O(OPEN)打开模块\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"例:打开1号模块:O1\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"例:全部打开:O\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"包含的模块:\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"TEST:%d 过滤:%d \r\n",LOG_TEST,Filter[LOG_TEST]);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"CLOCK:%d 过滤:%d \r\n",LOG_CLOCK,Filter[LOG_CLOCK]);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"DW1000:%d 过滤:%d \r\n",LOG_DW1000,Filter[LOG_DW1000]);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"DW1000_STATUS:%d 过滤:%d \r\n",LOG_DW1000_STATUS,Filter[LOG_DW1000_STATUS]);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"DW1000_DEAL_BUS:%d 过滤:%d \r\n",LOG_DEAL_BUS,Filter[LOG_DEAL_BUS]);
	console_tx((uint8_t *)log_out,strlen(log_out));
	strcpy(log_out,"*******************************************\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
}

/**
* @brief 输出本地日志
*/

static void print_log(void)
{
	char log_out[100] = {0};
	uint8_t i = 0;
	
	strcpy(log_out,"本地日志输出:\r\n");
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到移动点数据次数:%d\r\n", Log.num_rf_rx);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"发送超时被删除点数:%d\r\n", Log.num_time_out_delete);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"RF发送次数:%d\r\n", Log.num_rf_tx);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"RF校时或分配事件次数:%d\r\n", Log.num_rf_time);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"RF随机信道发送次数:%d\r\n", Log.num_rf_random_tx);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"复位次数:%d\r\n", Log.num_reset);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"运行时间:%d\r\n", Log.time_run);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到同步脉冲计数:%d\r\n", Log.num_sync_pulse);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到422轮询/事件帧次数:%d\r\n", Log.num_bus_poll);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到422事务命令次数:%d\r\n", Log.num_bus_down_cmd);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到422事务命令中事件个数:%d\r\n", Log.num_bus_down_cmd_dot);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到有效的422帧次数:%d\r\n", Log.num_valid_bus);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"收到无效的422帧次数:%d\r\n", Log.num_invalid_bus);
	console_tx((uint8_t *)log_out,strlen(log_out));
	sprintf(log_out,"校时时间错误次数:%d\r\n", Log.num_time_error);
	console_tx((uint8_t *)log_out,strlen(log_out));
	for (i = 0; i < NUM_DW1000; i++)
	{
		sprintf(log_out,"%d号dw1000模块错误次数:%d\r\n", i, Log.num_dw1000_error[i]);
		console_tx((uint8_t *)log_out,strlen(log_out));
	}
	for (i = 0; i < NUM_DW1000; i++)
	{
		sprintf(log_out,"%d号dw1000模块时间错误次数:%d\r\n", i, Log.num_dw1000_time_error[i]);
		console_tx((uint8_t *)log_out,strlen(log_out));
	}
	sprintf(log_out,"轮询超时被删除点数:%d\r\n", Log.num_poll_time_out_delete);
	console_tx((uint8_t *)log_out,strlen(log_out));
	for (i = 0; i < NUM_DW1000; i++)
	{
		sprintf(log_out,"%d号dw1000模块接收时间超时复位次数:%d\r\n", i, Log.num_dw1000_time_out_reset[i]);
		console_tx((uint8_t *)log_out,strlen(log_out));
	}
	for (i = 0; i < NUM_DW1000; i++)
	{
		sprintf(log_out,"%d号dw1000模块状态错误次数:%d\r\n", i, Log.num_dw1000_status_error[i]);
		console_tx((uint8_t *)log_out,strlen(log_out));
	}
}

/**
* @brief 处理动作
* @param index:动作编号
*/

static void deal_action(uint8_t index)
{
	uint32_t status = 0;
	char log_out[100] = {0};
	
	switch (index)
	{
		//读取1号dw1000状态寄存器
		case 1:
		{
			status = dwt_read32bitreg(0, SYS_STATUS_ID);
			sprintf(log_out,"1号dw1000状态:0x%08x\r\n", status);
			console_tx((uint8_t *)log_out,strlen(log_out));
			break;
		}
		//清除1号dw1000状态寄存器
		case 2:
		{
			status = dwt_read32bitreg(0, SYS_STATUS_ID);
			dwt_write32bitreg(0, SYS_STATUS_ID, status);
			break;
		}
		//打开1号dw1000接收
		case 3:
		{
			dwt_rxenable(0, 0);
			break;
		}
	}
}





2016-07-04 19:57:32 softn 阅读数 3435
为什么称之为单片机最小系统呢?单片机最小系统,也叫做单片机最小应用系统,是指用最少的原件组成单片机可以工作的系统。单片机最小系统的三要素就是电源、晶振、复位电路,如图 2-1 所示。
图 2-1  单片机最小系统电路
图 2-1  单片机最小系统电路

这张最小系统的电路图节选自我们的 KST-51 开发板原理图,下面我们就照这张电路图来具体分析最小系统的三要素。

1) 电源

这个很好理解,电子设备都需要供电,就连我们的家用电器(手电筒^_^)也不例外。目前主流单片机的电源分为 5V 和 3.3V 这两个标准,当然现在还有对电压要求更低的单片机系统,一般多用在一些特定场合,在学习中我们不做过多的关注。

我们所选用的 STC89C52,它需要 5V 的供电系统,我们的开发板是使用 USB 口输出的5V 直流直接供电的。从图 2-1 可以看到,供电电路在 40 脚和 20 脚的位置上,40 脚接的是+5V,通常也称为 VCC 或 VDD,代表的是电源正极,20 脚接的是 GND,代表的是电源的负极。+5V 和 GND 之间还有个电容,作用我们下节课介绍。

这个地方我们还要普及一个看原理图的知识。电路原理图是为了表达这个电路的工作原理而存在的,很多器件在绘制的时候更多考虑的是方便原理分析,而不是表达各个器件实际位置。比如原理图中的单片机引脚图,引脚的位置我们是可以随意放的,但是每个引脚上有一个数字标号,这个数字标号代表的才是单片机真正的引脚位置。一般情况下,这种双列直插封装的芯片,左上角是 1 脚,逆时针旋转引脚号依次增加,一直到右上角是最大脚位,我们现在选用的单片机一共是 40 个引脚,因此右上角就是 40(在表示芯片的方框的内部),如图 2-2 所示,大家要分清原理图引脚标号和实际引脚位置的区别。
图 2-2  单片机封装图
图 2-2  单片机封装图

2) 晶振

晶振,又叫晶体振荡器,从这个名字我们就可以看出来,它注定一生都要不停振荡的。

他起到的作用是为单片机系统提供基准时钟信号,类似于我们部队训练时喊口令的人,单片机内部所有的工作都是以这个时钟信号为步调基准来进行工作的。STC89C52 单片机的 18 脚和 19 脚是晶振引脚,我们接了一个 11.0592M 的晶振(它每秒钟振荡 11,059,200 次),外加两个 20pF 的电容,电容的作用是帮助晶振起振,并维持振荡信号的稳定。

3) 复位电路

在图 2-1 左侧是一个复位电路,接到了单片机的 9 脚 RST(Reset)复位引脚上,这个复位电路如何起作用我们后边再讲,现在着重讲一下复位对单片机的作用。单片机复位一般是 3种情况:上电复位、手动复位、程序自动复位。

假如我们的单片机程序有 100 行,当某一次运行到第 50 行的时候,突然停电了,这个时候单片机内部有的区域数据会丢失掉,有的区域数据可能还没丢失。那么下次打开设备的时候,我们希望单片机能正常运行,所以上电后,单片机要进行一个内部的初始化过程,这个过程就可以理解为上电复位,上电复位保证单片机每次都从一个固定的相同的状态开始工作。这个过程跟我们打开电脑电源开电脑的过程是一致的。

当我们的程序运行时,如果遭受到意外干扰而导致程序死机,或者程序跑飞的时候,我们就可以按下一个复位按键,让程序重新初始化重新运行,这个过程就叫做手动复位,最典型的就是我们电脑的重启按钮。

当程序死机或者跑飞的时候,我们的单片机往往有一套自动复位机制,比如看门狗,具体应用以后再了解。在这种情况下,如果程序长时间失去响应,单片机看门狗模块会自动复位重启单片机。还有一些情况是我们程序故意重启复位单片机。

电源、晶振、复位构成了单片机最小系统的三要素,也就是说,一个单片机具备了这三个条件,就可以运行我们下载的程序了,其他的比如 LED 小灯、数码管、液晶等设备都是属于单片机的外部设备,即外设。最终完成我们想要的功能就是通过对单片机编程来控制各种各样的外设实现的。
2015-04-06 11:38:00 u013675234 阅读数 725
单片机最小系统零件,可以选择是否加1602液晶

1、两个22pf的瓷片电容
2、排针(单片机两边)
3、晶振
4、10k的电阻 1个 (复位电路)
5、10uf的电解电容1个  (复位电路)
6、按键 1个 (复位电路)
7、51单片机一块
8、排阻  (液晶)
9、自锁开关  
10、电源指示灯
11、USB母口
12、液晶插槽
13、电位器
14、单片机插槽
2018-03-27 12:35:08 qq_35445306 阅读数 1769

51单片机最小系统的组成

51单片机最小系统的组成

51单片机最小系统需要一个下载接口、电源、复位电路及晶振电路组成。

51单片机最小系统电路原理图

51单片机最小系统电路原理图

晶振电路实物图

这里写图片描述

11.0592是代表晶振的频率越快,单片机的运行速度越快。
每个单片机的运行速度都是在一定范围内的。
晶振在使用时往往需要配置两个30F的电容。

51单片机led驱动原理

典型的led控制电路1

这里写图片描述

典型的led控制电路2

这里写图片描述

GND代表接地,VCC代表电源, 这里写图片描述 代表 发光二极管。


2018年3月27日12:32:24
QQ:201309512

2019-07-09 20:58:12 weixin_42832780 阅读数 59

一个单片机应用系统的硬件电路设计包含两部分内容:一是系统扩展,即单片机内部的功能单元,如ROM、RAM、I/O、定时器/计数器、中断系统等不能满足应用系统的要求时,必须在片外进行扩展,选择适当的芯片,设计相应的电路。二是系统的配置,即按照系统功能要求配置外围设备,如键盘、显示器、打印机、A/D、D/A转换器等,要设计合适的接口电路。

系统的扩展和配置应遵循以下原则:
1、尽可能选择典型电路,并符合单片机常规用法。为硬件系统的标准化、模块化打下良好的基础。
2、系统扩展与外围设备的配置水平应充分满足应用系统的功能要求,并留有适当余地,以便进行二次开发。
3、硬件结构应结合应用软件方案一并考虑。硬件结构与软件方案会产生相互影响,考虑的原则是:软件能实现的功能尽可能由软件实现,以简化硬件结构。但必须注意,由软件实现的硬件功能,一般响应时间比硬件实现长,且占用CPU时间。
4、系统中的相关器件要尽可能做到性能匹配。 如选用CMOS芯片单片机构成低功耗系统时,系统中所有芯片都应尽可能选择低功耗产品。
5、可靠性及抗干扰设计是硬件设计必不可少的一部分,它包括芯片、器件选择、去耦滤波、印刷电路板布线、通道隔离等。
6、单片机外围电路较多时,必须考虑其驱动能力。驱动能力不足时,系统工作不可靠,可通过增设线驱动器增强驱动能力或减少芯片功耗来降低总线负载。
7、尽量朝“单片”方向设计硬件系统。系统器件越多,器件之间相互干扰也越强,功耗也增大,也不可避免地降低了系统的稳定性。随着单片机片内集成的功能越来越强,真正的片上系统SoC已经可以实现,如ST公司新近推出的μPSD32××系列产品在一块芯片上集成了80C32核、大容量FLASH存储器、SRAM、A/D、I/O、两个串口、看门狗、上电复位电路等等。更多交流学习企鹅号2898829468,相互探讨学习

单片机最小系统

阅读数 29

没有更多推荐了,返回首页