当前位置:首页 > 单片机 > 单片机
[导读] 串口:一. USART_ITConfig(USART1, USART_IT_TXE, ENABLE):只要发送寄存器为空,就会一直有中断,因此,要是不发送数据时,把发送中断关闭,只在开始发送时,才打开。二.以下是字符发送的配置过程,注

串口

一. USART_ITConfig(USART1, USART_IT_TXE, ENABLE):

只要发送寄存器为空,就会一直有中断,因此,要是不发送数据时,把发送中断关闭,只在开始发送时,才打开。

二.

以下是字符发送的配置过程,注意第6点,在设置USART_CR1中的TE位时,会发送一个空闲帧作为第一次数据发送,所以即便你执行了USART_ClearFlag(USART1, USART_FLAG_TC); (这个函数肯定在空闲帧数据发送完成前执行),所以当空闲帧发送完后,就进入发送完成中断。

配置步骤:
1.通过在USART_CR1寄存器上置位UE位来激活USART
2.编程USART_CR1的M位来定义字长。
3.在USART_CR2中编程停止位的位数。
4.如果采用多缓冲器通信,配置USART_CR3中的DMA使能位(DMAT)。按多缓冲器通信中
的描述配置DMA寄存器。
5.利用USART_BRR寄存器选择要求的波特率。
6.设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。
7.把要发送的数据写进USART_DR寄存器(此动作清除TXE位)。在只有一个缓冲器的情况
下,对每个待发送的数据重复步骤7。
8.在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的
传输结束。当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏
最后一次传输。

解决的办法:
方法一
在执行USART_ITConfig(USART1,USART_IT_TC, ENABLE); 之前,
先延时一段时间,基本上比一个字符发送的时间长一点就可以了,然后再执行
USART_ClearFlag(USART1, USART_FLAG_TC);

方法二:
在执行USART_ITConfig(USART1,USART_IT_TC, ENABLE); 之前,
USART_ClearFlag(USART1, USART_FLAG_TC);

while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)
{
; //等待空闲帧发送完成后再清零发送标志
}
USART_ClearFlag(USART1,USART_FLAG_TC);

三.

TXE:发送缓冲器空闲标志

RXNE:接收缓冲区非空

IAP:

一.

问:

这几天在折腾STM32的IAP,参考了两个例程,一个AN2557,然后一个就是标准外设库内的flash例程

总结IAP:

1.Flash解锁FLASH_Unlock();

2.清除Flash所有的未完成的标志位FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);

3.根据文件大小擦除Flash
for(EraseCounter=0;(EraseCounter{
FLASHStatus=FLASH_ErasePage(StartAddr+(FLASH_PAGE_SIZE*EraseCounter));
}

4.编程Flash
while((Address{
FLASHStatus=FLASH_ProgramWord(Address,Data);
Address=Address+4;
}

5.检验编入数据的正确性
while((Address{
if((*(__IOuint32_t*)Address)!=Data)
{
MemoryProgramStatus=FAILED;
}
Address+=4;
}

在以上几步中,如果上面没有问题的话,提出下面几个疑问

1.假如我的应用程序的地址应该从0x8003000开始,那么我把后面的页全部擦除是否可以?虽然我的程序可能只占到0x8003000-0x8005000那么这之后的页是否也可以一并擦除?

2.在编程的时候有个很小的问题,因我的数据都是以字节(byte)的形式储存的,在写的时候因为只能以半字(16位)或一个字(32位)的方式编程,那么如果我的bin
文件的最后一个字节并不够两个字节,怎么办?举例:我的bin文件的大小是501个字节(8位),我的写入方法是这样的:
data[501]={X,X,X...}//应用程序bin文件内容
temp=data[0];
temp=temp<<8;
temp|=data[1];
temp=temp<<8;
temp|=data[2];
teme=temp<<8;
teme|=data[3];//待写入得数据

FLASHStatus=FLASH_ProgramWord(Address,temp);//写入flash

如果像这样的话,那么不能被4整除的那一个字节怎么办?

3.IAP程序中有一处一直很迷惑,不能理解
/*Testifusercodeisprogrammedstartingfromaddress"ApplicationAddress"*/
if(((*(__IOuint32_t*)ApplicationAddress)&0x2FFE0000)==0x20000000)
{/*Jumptouserapplication*/
JumpAddress=*(__IOuint32_t*)(ApplicationAddress+4);
Jump_To_Application=(pFunction)JumpAddress;
/*Initializeuserapplication'sStackPointer*/
__set_MSP(*(__IOuint32_t*)ApplicationAddress);
Jump_To_Application();
}
程序的整体是要跳出IAP引导区跳到应用程序区.那么这句判断的依据是什么?if(((*(__IOuint32_t*)ApplicationAddress)&0x2FFE0000)==0x20000000)
倘若我今天的程序是重0x8003000处开始,那么明天我升级一个程序,他的开始是0x80080000呢?这里需要改吗?

0x2FFE00000x20000000这两个数我在AN2557的例子代码里反复寻找,并没有哪里出现,那么又是怎么跟用户的应用程序关联的呢?

还有如果将上面的例子直接这样更改,是否可以达到跳转到应用程序区的目的呢?
/*Jumptouserapplication*/
JumpAddress=*(__IOuint32_t*)(ApplicationAddress+4);//这里为何要+4?+了4不就跳过出应用程序的入口了吗?
Jump_To_Application=(pFunction)JumpAddress;
/*Initializeuserapplication'sStackPointer*/
__set_MSP(*(__IOuint32_t*)ApplicationAddress);
Jump_To_Application();

4.关于Flash的写保护问题,在3.0标准外设库中Flash还有另外一个例子,就是关于保护的
无疑flash的保护是对程序的一个安全保障,但目前我买的新片子(未进行过任何保护方面的操作)中,是否不需要考虑这些问题,直接擦除,然后编程即可?

5.有什么理由要“今天的程序是重0x8003000处开始,明天又升级一个程序,他的开始是呢”?第1没有必要,第2是自寻烦恼。开始地址是你自己定的,为什么要自己为难自己?

这个问题怪我没说清楚,其实我是想说,我现在的引导区这样定义的#ApplicationAddress0x80030000我只能启动起始地址在0x08003000处的应用程序,那么这段代码是可以成功启动的(我验证过):
/*Testifusercodeisprogrammedstartingfromaddress"ApplicationAddress"*/
if(((*(__IOuint32_t*)ApplicationAddress)&0x2FFE0000)==0x20000000)
{/*Jumptouserapplication*/
JumpAddress=*(__IOuint32_t*)(ApplicationAddress+4);
Jump_To_Application=(pFunction)JumpAddress;
/*Initializeuserapplication'sStackPointer*/
__set_MSP(*(__IOuint32_t*)ApplicationAddress);
Jump_To_Application();
}

那如果我现在想引导启动地址在0x80080000的应用程序,是否只要更改#ApplicationAddress0x80080000这句就好?上面那串代码就不需要更改了吧?

我还是想理解了上面的那串代码到底是为什么?希望香版能仔细帮我解释下,(当我白痴好了,呵呵)!

答:

1.可以,只要不影响功能就行
2.比较好的解决方法,先读一页出来到RAM,擦掉这一页Flash,在RAM中修改相应的Bytes,再将整页写回去。 一般的解决方法,后面不足一个WORD/DWORD的补0xff或0x00,补齐一个WORD或DWORD

3.ApplicationAddress对应着你的应用程序"stm32f10x_vector.c"这个文件中的__vector_table
*(__IOuint32_t*)ApplicationAddress与__vector_table[0]是一样的
*(__IOuint32_t*)(ApplicationAddress+4)与__vector_table[1]是一样的
__vector_table[0]是应用程序栈的顶
__vector_table[1]是应用程序的启动地址
这里有讨论过
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=1600156&bbs_page_no=3&bbs_id=3020

(X&0x2FFE0000)==0x20000000意思是说X是不是在0x20000000与0x2001FFFF之间,即栈顶是不是在以0x20000000开始的128K

的范围内,这里便是STM32的RAM区域,虽然现在最大的只有64k

如果你的bootloader只能启动0x08003000的应用程序,那么你写一个起始地址在0x08008000的程序他将不能启动
你要写一个在0x080003000的启动程序来启动0x08008000的应用程序,或者把0x08008000前八字节的内容放到0x08003000中

4.是的,买回来的可以直接写,出厂时芯片的Flash都没有设置保护。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭