2018-04-03 20:47:34 jiayoudangdang 阅读数 2180
  • 温度传感器DS18B20-第2季第1部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第1个课程,主要讲解单片机系统中常用的温度传感器DS18B20。本课程的目标是让大家进一步掌握时序的分析和编程实现,学会移植和调试DS18B20的程序,能够读取温度。

    2182 人正在学习 去看看 朱有鹏

为何单片机的程序必须是死循环?!!

这个问题困扰了我好久,然而答案却是这个样子的!

单片机没有操作系统,不像电脑有Windows,程序运行与结束有操作系统管理。单片机的程序是不能结束的,否则会使单片机系统出现不确定的状态;
一般编译会自己加上
如果汇编写,一般不用做循环 
2019-09-27 16:02:07 Lin_LYFC 阅读数 127
  • 温度传感器DS18B20-第2季第1部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第1个课程,主要讲解单片机系统中常用的温度传感器DS18B20。本课程的目标是让大家进一步掌握时序的分析和编程实现,学会移植和调试DS18B20的程序,能够读取温度。

    2182 人正在学习 去看看 朱有鹏

单片机的程序升级其实本质就是对单片机的片上Flash进行擦写,将新的程序写入到运行的Flash位置。做了2G模块的IAP程序升级和基于串口上位机的IAP程序升级。写下一点自己的浅见。

概况:

  1. 软件上:
    具备远程升级的单片机的程序整体具体包含两个部分,一部分是(APP)应用程序,另一部分是(BOOT)引导程序
    APP程序 就是我们需要进行更新的程序,程序包括的内容:应用相关的程序(业务相关),接受并解析升级数据包的程序,存储数据包的程序。
    BOOT程序 
    就是负责对已经存储好的升级数据包文件写入APP程序所在的Flash;并跳转到APP程序
    这两部分的程序是相互独立的运行的,拥有相互跳转的能力,相互升级对方的能力。上电一般先运行BOOT程序,然后跳转到APP程序执行。BOOT程序一般很小,APP程序比较大。

  2. 硬件上:
    单Flash块的单片机:Flash存储位置上BOOT程序从默认启动Flash地址 0x0000000 开始开始存储 ,APP程序从BOOT 程序后的指定Flash页的基地址开始(Flash擦除写入以页(page)为单位)。
    多个Flash块的单片机:单片机有相应的Flash区分(例如LDROM,APROM等),一般将两个程序存储与不同的区块,查看手册配置好,启动flash即可。
    如下图所示:

1. BOOT程序结构:

  •   单块Flash的BOOT程序结构简单(单片机为新唐的M4系列,使用复位跳转方式。也可以使用非重启方式跳转:重映射向量表之后,栈指针也要修改到APP_ADDR,(APP_ADDR + 4) 复位中断处理函数为程序入口),如下:
//只是示意步骤,并非真正程序,隐去细节
int32_t main(void)
{
    SYS_Init(); //系统以及外设初始化

    SYS_UnlockReg(); //解锁系统寄存器的写保护

    FMC_Open();    //开启Flash擦写

    set_IAP_boot_mode(); //进入IAP模式

    if(CheckUpdateFlag()) //检查是否需要升级APP程序
    {
        if(DataCheck()) //检验待写入的APP数据的完整性
        {
            FMC_ENABLE_AP_UPDATE(); //开启程序区的Falsh写入

            load_image_to_flash(); //写入新的APP程序

            WriteUpdateFlag(Update_Success); //更新升级标志位至升级完成
            
            FMC_DISABLE_AP_UPDATE(); //关闭程序区的Falsh写入
        }
        else
        {
            WriteUpdateFlag(Update_Failed); //更新升级标志位至升级完成
        }    
    } 

    NVIC->ICER[0] = 0xFFFFFFFF; //关闭所有中断

    FMC_SetVectorPageAddr(APP_ADDR); //重定向APP程序执行向量,页对齐

    NVIC_SystemReset();	//重启跳转至APP程序,或者使用程序跳转

}
  • 多块Flash的情况:只是将跳转的方式的操作有所区别,基本一致。

2. APP程序结构:

APP程序的程序升级流程就把从数据源获取的数据(不管是网络传输过来的数据,还是通过串口传输的数据),按照约定的格式解析出APP的二进制数据包和程序的校验值存储起来,在接收完毕数据之后把升级的标志位置为需要升级,然后执行跳转到BOOT程序,进行升级。新的APP程序,检查升级是否完成的,上报或者回复相应信息。

至此升级流程就全部完成。这里只讲流程,由于传输的方式和传输协议等的差异,具体的实现方式很多。

3. Flash写入相关:

一般升级文件为单片机工程编译生成的BIN文件,传输量最小。Hex文件大小至少是BIN文件的2倍。

例如如上图所示,数据存储于片上Flash的另一区域,那么一般这块数据的第一页都是用来存放数据包的信息,校验值,升级标志位等升级相关的数据。升级文件的Flash写入就是将BIN文件原封不动的从Flash指定地址(例如APP_ADDR)开始写入,不足一页的用0xFF填充剩下的字节写入。

 

题外话:现在单片机的功能越来越强大,主频也越来越高,像Coretex-M7的已经达到了500MHz。相应的应用也是越来越丰富,互联网思维(敏捷开发)的全行业推进,做一款产品先做一个demo先上线,然后根据实际情况慢慢的完善。这时候程序的升级就变得非常的重要了,你要是联网的的设备远程升级那就更加的方便了。IAP升级也适用于功能出了问题进行紧急维护。

2019-08-27 09:44:13 weixin_42832780 阅读数 10
  • 温度传感器DS18B20-第2季第1部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第1个课程,主要讲解单片机系统中常用的温度传感器DS18B20。本课程的目标是让大家进一步掌握时序的分析和编程实现,学会移植和调试DS18B20的程序,能够读取温度。

    2182 人正在学习 去看看 朱有鹏

1、采用短变量

一个提高代码效率的最基本的方式就是减小变量的长度。使用 C 编程时,我们都习惯于对循环控制变量使用 int 类型,这对 8 位的单片机来说是一种极大的浪费,你应该仔细考虑你所声明的变量值可能的范围,然后选择合适的变量类型,很明显,经常使用的变量应该是unsigned char,只占用一个字节。

2、使用无符号类型

为什么要使用无符号类型呢?原因是8051不支持符号运算,程序中也不要使用含有带符号变量的外部代码,除了根据变量长度来选择变量类型外,你还要考虑是否变量是否会用于负数的场合。如果你的程序中可以不需要负数那么把变量都定义成无符号类型的。

3、避免使用浮点指针

在 8 位操作系统上使用 32 位浮点数是得不偿失的。你可以这样做,但会浪费大量的时间,所以当你要在系统中使用浮点数的时候,你要问问自己这是否一定需要,可以通过提高数值数量级和使用整型运算来消除浮点指针,处理ints和longs比处理doubles和floats要方便得多,你的代码执行起来会更快,也不用连接处理浮点指针的模块。如果你一定要,采用浮点指针的话,你应该采用西门子 80517 和达拉斯半导体公司的 80320 这些已经对数,处理进行过优化的单片机。如果你不得不在你的代码中加入浮点指针,那么你的代码长度会增加程序执行速度也会比较慢。如果浮点指针运算能被中断的话,你必须确保要么中断中不会使用浮点指针运算,要么在中断程序前使用 fpsave 指令把中断指针推入堆栈,在中断程序执行后使用 fprestore 指令把指针恢复,还有一种方法是,当你要使用像 sin()这样的浮点运算程序时,禁止使用中断,在运算程序执行完之后再使能它。

4、使用位变量

对于某些标志位应使用位变量而不是 unsigned char,这将节省你的内存,你不用多浪费7位存储区,而且位变量在RAM中访问他们只需要一个处理周期。

5、用局部变量代替全局变量

把变量定义成局部变量比全局变量更有效率,编译器为局部变量在内部存储区中分配存储空间,而为全局变量在外部存储区中分配存储空间,这会降低你的访问速度,另一个避免使用全局变量的原因是你必须在你系统的处理过程中调节使用全局变量,因为在中断系统和多任务系统中,不止一个过程会使用全局变量。

6、为变量分配内部存储区

局部变量和全局变量可被定义在你想要的存储区中,根据先前的讨论,当你把经常使用的变量放在内部 RAM 中时,可使你的程序的速度得到提高,除此之外,你还缩短了你的代码,因为外部存储区寻址的指令相对要麻烦一些考虑到存储速度,按下面的顺序使用存储器DATA IDATA PDATA XDATA,当然你要记得留出足够的堆栈空间。

7、使用特定指针

当你在程序中使用指针时,你应指定指针的类型确定它们指向哪个区域如 XDATA 或CODE 区,这样你的代码会更加紧凑,因为编译器不必去确定指针所指向的存储区,因为你已经进行了说明。

8、使用调令

对于一些简单的操作,如变量循环位移,编译器提供了一些调令供用户使用,许多调令直接对应着汇编指令,而另外一些比较复杂并兼容 ANSI 所有这些调令都是再入函数,你可在任何地方安全的调用他们和单字节循环位移指令 RL A 和 RR A 相对应的调令是_crol_ 循环左移 和_cror_(循环右移)。如果你想对 int 或 long 类型的变量进行循环位移,调令将更加复杂而且执行的时间会更长 对于 int 类型调令为_irol_,iror ,对于 long 类型调令为_lrol_,lror。在 C 中也提供了像汇编中 JBC 指令那样的调令_testbit_ ,如果参数位置位他将返回1,否则将返回 0 这条调令在检查标志位时十分有用,而且使 C 的代码更具有可读性调令将直接转换成 JBC 指令。

#include <instrins.h>
void serial_intr(void) interrupt 4 {
if (!testbit(TI)) { // 是否是发送中断
P0=1; // 翻转 P0.0
nop(); // 等待一个指令周期
P0=0;

}
if (!testbit(RI)) {
test=cror(SBUF, 1); // 将SBUF中的数据循环
// 右移一位

}
}
9、使用宏替代函数

对于小段代码,像使能某些电路或从锁存器中读取数据,你可通过使用宏来替代函数使得程序有更好的可读性你可把代码定义在宏中,这样看上去更像函数。编译器在碰到宏时,按照事先定义的代码去替代宏,宏的名字应能够描述宏的操作,当需要改变宏时,你只要修该宏定义处。

#define led_on() {
led_state=LED_ON;
XBYTE[LED_CNTRL] = 0x01;}
#define led_off() {
led_state=LED_OFF;
XBYTE[LED_CNTRL] = 0x00;}
#define checkvalue(val)
( (val < MINVAL || val > MAXVAL) ? 0 : 1 )
宏能够使得访问多层结构和数组更加容易,可以用宏来替代程序中经常使用的复杂语句以减少你打字的工作量且有更好的可读性和可维护性。

10、存储器模式

C51提供了 3 种存储器模式来存储变量、过程参数和分配再入函数堆栈。你应该尽量使用小存储器模式,很少应用系统需要使用其它两种模式,像有大的再入函数堆栈系统那样。一般来说如果系统所需要的内存数小于内部RAM 数时,都应以小存储模式进行编译。在这种模式下 DATA 段是所有内部变量和全局变量的默认存储段,所有参数传递都发生在DATA 段中,如果有函数被声明为再入函数,编译器会在内部 RAM 中为他们分配空间,这种模式的优势就是数据的存取速度很快,但只有120个字节的存储空间供你使用,总共有128个字节,但至少有8个字节被寄存器组使用,你还要为程序调用开辟足够的堆栈。如果你的系统有 256 字节或更少的外部 RAM 你可以使用压缩存储模式。这样一来,如果不加说明,变量将被分配在 PDATA 段中,这种模式将扩充你能够使用的 RAM 数量,对XDATA 段以外的数据存储仍然是很快的,变量的参数传递将在内部 RAM 中进行,这样存储速度会比较快,对 PDATA 段的数据的寻址是通过 R0 和R1进行间接寻址,比使用 DPTR 要快一些在大存储模式中,所有变量的默认存储区是 XDATA 段 Keil C 尽量使用内部寄存器组进行参数传递,在寄存器组中可以传递参数的数量和和压缩存储模式一样,再入函数的模拟栈将在 XDATA中 对 XDATA 段数据的访问是最慢的,所以要仔细考虑变量应存储的位置使数据的存储速度得到优化。

11、混合存储模式

Keil 允许使用混合的存储模式,这点在大存储模式中是非常有用的。在大存储器模式下,有些过程对数据传递的速度要求很高。我就把过程定义在小存储模式寄存器中,这使得编译器为该过程的局部变量在内部 RAM中分配存储空间,并保证所有参数都通过内部 RAM进行传递。尽管采用混合模式后编译的代码长度不会有很大的改变,但这种努力是值得的就像能在大模式下把过程声明为小模式一样,你像能在小模式下把过程声明为压缩模或大模式,这一般使用在需要大量存储空间的过程上,这样过程中的局部变量将被存储在外部存储区中,你也可以通过过程中的变量声明,把变量分配在 XDATA 段中。

12、运行库

运行库中提供了很多短小精悍的函数,你可以很方便的使用他们,你自己很难写出更好的代码了。值得注意的是库中有些函数不是再入函数,如果在执行这些函数的时候被中断,而在中断程序中又调用了该函数,将得到意想不到的结果。而且这种错误很难找出来,最好禁止使用这些函数的中断。更多交流分享私聊我vx132陆零伍陆2029

2019-02-14 00:05:22 qq_42860728 阅读数 1838
  • 温度传感器DS18B20-第2季第1部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第1个课程,主要讲解单片机系统中常用的温度传感器DS18B20。本课程的目标是让大家进一步掌握时序的分析和编程实现,学会移植和调试DS18B20的程序,能够读取温度。

    2182 人正在学习 去看看 朱有鹏

51系列单片机程序

关于常闭型震动传感器51单片机的程序我这里提供两种方法供大家参考。

1、运用定时器中断

程序如下:

*****************************************/
#include<reg52.h>
unsigned char date;
#define uchar unsigned char
#define uint unsigned int
sbit key1=P0^1;

/* 函数申明 -----------------------------------------------*/
void delay(uint z);
void Initial_com(void);

/*
********************************************************************************
** 函数名称 : delay(uint z)
** 函数功能 : 延时函数
********************************************************************************
*/
void delay(uint z)
{
uint i,j;
for(i=z;i>0;i--)
for(j=110;j>0;j--);
}

/*
********************************************************************************
** 串口初始化函数
********************************************************************************
*/
void Initial_com(void)
{
EA=1; //开总中断
ES=1; //允许串口中断
ET1=1; //允许定时器T1的中断
TMOD=0x20; //定时器T1,在方式2中断产生波特率
PCON=0x00; //SMOD=0
SCON=0x50; // 方式1 由定时器控制
TH1=0xfd; //波特率设置为9600
TL1=0xfd;
TR1=1; //开定时器T1运行控制位
}
 

/*
********************************************************************************
**主函数
********************************************************************************
*/
main()
{
Initial_com();
while(1)
{

if(key1==1)
{
delay(); //消抖动
if(key1==1) //确认触发
{
SBUF=0X01;
delay(200);


}

}

if(RI)
{
date=SBUF; //单片机接受
SBUF=date; //单片机发送
RI=0;
}


}
}

感兴趣的童鞋可以参考一下。

2、运用外部中断

程序如下:

#include<reg52.h>
unsigned char date;
#define uchar unsigned char
#define uint unsigned int
sbit key1=P1^0;//模块D0接口
uint flag = 0;
sbit Beep = P1^5;
/*  ---------------------函数申明--------------------------*/
void delay(uint z);
void beep(uint m, uint k);

/*
********************************************************************************
** 函数名称 : delay(uint z)
** 函数功能 : 延时函数
********************************************************************************
*/
void delay(uint z)
{
	uint i,j;
	for(i=z;i>0;i--)
		for(j=110;j>0;j--);
}


/*
********************************************************************************
**	定义蜂鸣器函数
********************************************************************************
*/
void beep(uint m, uint k) //修改参数可改变蜂鸣器音调
{
	uchar i = 0;
	uint j = 0;
	for(j = m;j > 0;j --)
	{
		for(i = 0;i <= 50; i++)
		{
			Beep = ~Beep;
			delay(k);
		}
	}
}

/*
********************************************************************************
**	主函数
********************************************************************************
*/
main()
{
	IT0 = 1;                        //set INT0 int type (1:Falling 0:Low level)
	EX0 = 1;                        //enable INT0 interrupt
	EA = 1 ;
	while(1)
{

if(flag==1)
{
	delay(); //消抖动
	if(key1==1) //确认触发
	{
		SBUF=0X01;
		beep(3,1);
		delay(200);
}

}

if(RI=0)
	{
		date=SBUF; //单片机接受
		SBUF=date; //单片机发送
		RI=1;
}

}
}
void exint0() interrupt 0           //(location at 0003H)
{
	if(key1==0)	
		flag = 1;
	delay(100);	
}

在这个程序中我加入了蜂鸣器,实现的现象是:上电接入震动模块,每震动一次蜂鸣器便响一下,应用起来特别方便。

Arduino程序

地址:
震动传感器Arduino程序的应用

2019-10-15 15:47:26 qiudebenge 阅读数 73
  • 温度传感器DS18B20-第2季第1部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第1个课程,主要讲解单片机系统中常用的温度传感器DS18B20。本课程的目标是让大家进一步掌握时序的分析和编程实现,学会移植和调试DS18B20的程序,能够读取温度。

    2182 人正在学习 去看看 朱有鹏

下文来说明单片机与x86cpu的具体途径:

pc机在运行程序的时候先把程序从硬盘中,调入RAM中运行,cpu从RAM中读取程序和数据.

而单片机的程序则是固化在flash 中,cpu运行的时候直接从flash 中读取程序,从RAM中读取数据.

造成这种差别的原因:

x86架构的cpu是基于冯.诺伊曼体系的,即数据和程序储存在一起,而且pc机的RAM资源相当丰富,从几十M到几百M甚至是几个G,客观上能承受大量的程序数据.

而单片机的架构大多是哈弗体系的,即程序和数据分开储存,而且单片机的片内RAM资源是相当有限的,内部的RAM过大会带来成本的大幅度提高.

单片机的程序能存储在RAM中吗
通过上面的分析可得知:单片机的程序能存储于flash中是基于两点考虑,即体系结构和RAM资源的多少.因此,在技术不但进步片内RAM容量不但增多的今天,RAM资源已经不再是制约这种差别的主要因素,而对于体系机构我们只要更改cpu读取程序的方式就可以.
我仔细研究了一下链接脚本,用的是gnu的linux的交叉工具链.地址分配是写在一个ld脚本中的.
他们是这样实现的:
1,将你需要在ram中运行的代码写在单独的一个c文件中,然后在脚本中设置其运行地址与存放地址分开.设置好必要的代码起始和结束的标志变量.

2,在代码中将存放地址处的代码拷贝到运行地址中.

冯.诺依曼体系与哈佛体系的区别
二者的区别就是程序空间和数据空间是否是一体的. 早期的微处理器大多采用冯诺依曼结构,典型代表是Intel公司的X86微处理器.取指令和取操作数都在同一总线上,通过分时复用的方式进行的.缺点是在高速运行时,不能达到同时取指令和取操作数,从而形成了传输过程的瓶颈.
哈佛总线技术应用是以DSP和ARM为代表的.采用哈佛总线体系结构的芯片内部程序空间和数据空间是分开的,这就允许同时取指令和取操作数,从而大大提高了运算能力.
例如TMS320LF240x系列DSP是增强型的哈佛结构通过三组并行的总线访问多个存储空间.它们分别是:程序地址总线(PAB),数据地址读总线(DRAB)和数据地址写总线(DWRB).

 

新系列:51单片机

阅读数 474

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