【IoT】STM32 启动代码 __main 与用户主程序 main() 的区别

1、__main 作用

__main函数是C/C++运行时库的一个函数,嵌入式系统在进入应用主程序之前必须有一个初始化的过程,使用__main标号引导系统时必须将应用程序的入口定义为main()。
    
在初始化的过程中,__main函数的作用主要有两点:

1) 完成对映像文件的初始化操作

a、映像文件

链接器把多个目标文件链接成一个映像文件。

b、加载地址和执行地址

映像文件可以有两种地址:加载地址和执行地址。

加载地址是映像文件在存储器中的存储地址;执行地址就是映像文件运行时的地址。

c、加载域和执行域

文件加载的存储区叫加载域,文件运行的存储区叫执行域。

d、从加载地址到执行地址

在结构比较简单的系统中,加载地址就是执行地址;

而在复杂系统中,程序运行前,常常会把映像文件的一部分或全部从存储区域移出去,此时执行地址就不再是加载地址。

知道以上几个概念,__main函数对映像文件的初始操作就不难理解了。

对于加载地址和执行地址不同的映像文件,__main函数会把加载地址的代码和数据复制到执行地址中,并且对被链接器指定为需要初始化为0的段,进行清零操作。

2) 调用__rt_entry函数,进入用户程序。

__rt_entry函数的运行流程如图:

 2、进入主程序

当所有的系统初始化工作完成之后,就需要把程序流程转入主应用程序,即呼叫主应用程序。

最简单的一种情况是:

IMPORT main

B main

直接从启动代码跳转到应用程序的主函数入口,当然主函数名字可以由用户随便定义。

在ARM ADS环境中,还另外提供了一套系统级的呼叫机制。

IMPORT __main

B __main

__main()是编译系统提供的一个函数,负责完成库函数的初始化和初始化应用程序执行环境,最后自动跳转到main()。

所以说,前者是库函数,后者就是我们自己编写的main()主函数;

因此我们用的B __main其实是执行库函数,然后该库函数再调用我们的main() 函数,因此在单步调试时会看到先要跑一段程序(其实是库函数),然后再单步到我们自己的main函数(这个同时也说明如果有B __main 则就对应必须有main函数,否则编译出错);

如果我们用 B main来进入我们的主函数的话,那在单步调试时就看到直接进入到我们自己的main函数了,中间不会看到其他程序;

那么用B __main和用B main 这两这进入我们的main函数方式有什么不同呢?

如果采用前者则会由编译器加入一段"段拷贝"程序,即我们说的从加载域到执行域转化程序;而采用后者就没有这个了;

因此如果要进行 "段拷贝"只能自己动手编写程序来实现了,完成段拷贝后就可以进入我们的主函数了,当然这个主函数不一定是叫做main(),可以起个其他好听的名字,这个有别于使用B __main方式;不管采用哪种方式进入我们的程序,都要有一段"段拷贝"程序,跑完了段拷贝后才能可以进入我们主程序了。

startup.s 这个文件并没有所谓的"段拷贝"功能。

对含有启动程序来说,"执行地址与加载地址相同"不容易实现:

如果执行地址与加载地址相同哪当然不需要做"段拷贝",但是个人理解编译器还会加入"段拷贝"程序(如果用B __main 的话),只是因为条件不满足而不执行而已;但是对含有启动程序来说,"执行地址与加载地址相同"就不容易了.因为启动程序是要烧到非易失存储器里,用来在上电执行的,而这个程序必定会有RW段,如果RW放在非易失存储器,如FLASH,那就不好实现RW功能了,因此要给RW移动到能够实现RW功能的存储器,如SRAM等.因此,对含有启动程序来说,"执行地址与加载地址相同"就不容易实现;程序的入口点在C 库中的__main 处,在该点,库代码执行以下操作:

1)将非零(只读和读写)运行区域从其载入地址复制到运行地址。

2)清零ZI 区域。

3)跳转到__rt_entry。

 

 


refer:

https://www.cnblogs.com/dwj411024/p/7679345.html


 

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MQTT(Message Queuing Telemetry Transport)是一种轻量级的、基于发布/订阅模式的消息传输协议,它可以在不同网络间进行快速传输,适用于物联网应用。STM32是意法半导体推出的一款嵌入式微控制器。在STM32上实现MQTT需要使用MQTT客户端库,比如Paho MQTT,然后编写STM32代码来调用Paho MQTT库实现MQTT通信。 在STM32上实现MQTT通信,一般需要完成以下几个步骤: 1. 导入Paho MQTT库:将Paho MQTT库的代码添加到STM32的工程中,并进行编译。 2. 配置网络连接:为STM32配置网络连接方式,比如Wi-Fi、以太网等。 3. 创建MQTT客户端:在STM32代码中创建一个MQTT客户端实例,并设置连接参数,如服务器地址、端口号、用户名和密码等。 4. 连接MQTT服务器:使用MQTT客户端实例连接MQTT服务器。 5. 发布和订阅消息:使用MQTT客户端实例进行消息的发布和订阅操作。 6. 处理接收到的消息:当收到消息时,通过回调函数对消息进行处理。 以下是一个简单的使用Paho MQTT库在STM32上实现MQTT通信的示例代码: ```c #include "MQTTClient.h" #define MQTT_SERVER_ADDRESS "tcp://iot.eclipse.org:1883" #define MQTT_CLIENT_ID "example_client_id" #define MQTT_TOPIC "example_topic" Network network; MQTTClient client; void messageArrived(MessageData* data) { printf("Message arrived: %.*s\n", data->message->payloadlen, (char*) data->message->payload); } int main() { char buf[100]; int rc = 0; MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer; // Connect to network network_connect(&network); // Initialize MQTT client MQTTClient(&client, &network, 3000, buf, 100); // Configure connect data connectData.MQTTVersion = 4; connectData.clientID.cstring = MQTT_CLIENT_ID; // Connect to MQTT server if ((rc = MQTTConnect(&client, &connectData)) != 0) { printf("Failed to connect, return code %d\n", rc); return -1; } // Subscribe to topic if ((rc = MQTTSubscribe(&client, MQTT_TOPIC, QOS0, messageArrived)) != 0) { printf("Failed to subscribe, return code %d\n", rc); return -1; } while (1) { // Publish message char payload[20] = "Hello, world!"; MQTTMessage message; message.qos = QOS0; message.retained = 0; message.dup = 0; message.payload = (void*) payload; message.payloadlen = strlen(payload) + 1; if ((rc = MQTTPublish(&client, MQTT_TOPIC, &message)) != 0) { printf("Failed to publish, return code %d\n", rc); break; } } // Disconnect from MQTT server MQTTDisconnect(&client); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值