void main(void) - the Wrong Thing

本文详细解析了C和C++中main函数的正确定义方式,解释了voidmain()为何是错误的,并介绍了main函数返回值的重要作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很多人甚至市面上的一些书籍,都使用了void main( ) ,其实这是错误的。C/C++ 中从来没有定义过void main( ) 。C++ 之父 Bjarne Stroustrup 在他的主页上的 FAQ 中明确地写着 The definition void main( ) { /* ... */ } is not and never has been C++, nor has it even been C.( void main( ) 从来就不存在于 C++ 或者 C )。下面我分别说一下 C 和 C++ 标准中对 main 函数的定义。

1. C
        在 C89 中,main( ) 是可以接受的。Brian W. Kernighan 和 Dennis M. Ritchie 的经典巨著 The C programming Language 2e(《C 程序设计语言第二版》)用的就是 main( )。不过在最新的 C99 标准中,只有以下两种定义方式是正确的:

           int main( void )
           int main( int argc, char *argv[] )

(参考资料:ISO/IEC 9899:1999 (E) Programming languages — C 5.1.2.2.1 Program startup)

        当然,我们也可以做一点小小的改动。例如:char *argv[] 可以写成 char **argv;argv 和 argc 可以改成别的变量名(如 intval 和 charval),不过一定要符合变量的命名规则。
        如果不需要从命令行中获取参数,请用int main(void) ;否则请用int main( int argc, char *argv[] ) 。
        main 函数的返回值类型必须是 int ,这样返回值才能传递给程序的激活者(如操作系统)。
        如果 main 函数的最后没有写 return 语句的话,C99 规定编译器要自动在生成的目标文件中(如 exe 文件)加入return 0; ,表示程序正常退出。不过,我还是建议你最好在main函数的最后加上return 语句,虽然没有这个必要,但这是一个好的习惯。注意,vc6不会在目标文件中加入return 0; ,大概是因为 vc6 是 98 年的产品,所以才不支持这个特性。现在明白我为什么建议你最好加上 return 语句了吧!不过,gcc3.2(Linux 下的 C 编译器)会在生成的目标文件中加入 return 0; 。

2. C++
        C++98 中定义了如下两种 main 函数的定义方式:

                  int main( )
                  int main( int argc, char *argv[] )

(参考资料:ISO/IEC 14882(1998-9-01)Programming languages — C++ 3.6 Start and termination)

        int main( ) 等同于 C99 中的 int main( void ) ;int main( int argc, char *argv[] ) 的用法也和 C99 中定义的一样。同样,main 函数的返回值类型也必须是int。如果main函数的末尾没写return语句,C++98 规定编译器要自动在生成的目标文件中加入 return 0; 。同样,vc6 也不支持这个特性,但是 g++3.2(Linux 下的 C++ 编译器)支持。

3. 关于 void main
        在 C 和 C++ 中,不接收任何参数也不返回任何信息的函数原型为“void foo(void);”。可能正是因为这个,所以很多人都误认为如果不需要程序返回值时可以把main函数定义成void main(void) 。然而这是错误的!main 函数的返回值应该定义为 int 类型,C 和 C++ 标准中都是这样规定的。虽然在一些编译器中,void main 可以通过编译(如 vc6),但并非所有编译器都支持 void main ,因为标准中从来没有定义过 void main 。g++3.2 中如果 main 函数的返回值不是 int 类型,就根本通不过编译。而 gcc3.2 则会发出警告。所以,如果你想你的程序拥有很好的可移植性,请一定要用 int main 。

4. 返回值的作用
        main 函数的返回值用于说明程序的退出状态。如果返回 0,则代表程序正常退出,否则代表程序异常退出。下面我们在 winxp 环境下做一个小实验。首先编译下面的程序:

           int main( void )
           {
                  return 0;
           }


然后打开附件里的“命令提示符”,在命令行里运行刚才编译好的可执行文件,然后输入“echo %ERRORLEVEL%”,回车,就可以看到程序的返回值为 0 。假设刚才编译好的文件是 a.exe ,如果输入“a && dir”,则会列出当前目录下的文件夹和文件。但是如果改成“return -1”,或者别的非 0 值,重新编译后输入“a && dir”,则 dir 不会执行。因为 && 的含义是:如果 && 前面的程序正常退出,则继续执行 && 后面的程序,否则不执行。也就是说,利用程序的返回值,我们可以控制要不要执行下一个程序。这就是 int main 的好处。如果你有兴趣,也可以把 main 函数的返回值类型改成非 int 类型(如 float),重新编译后执行“a && dir”,看看会出现什么情况,想想为什么会出现那样的情况。顺便提一下,如果输入 a || dir 的话,则表示如果 a 异常退出,则执行 dir 。

5. 那么 int main( int argc, char *argv[], char *envp[] ) 呢?
    这当然也不是标准 C 里面定义的东西!char *envp[] 是某些编译器提供的扩展功能,用于获取系统的环境变量。因为不是标准,所以并非所有编译器都支持,故而移植性差,不推荐使用。

 

转载声明: 本文转自 http://bbs.pfan.cn/showtxt.asp?id=176821 (编程爱好者网站)

=========================================================================

 

我可以写“void main()”吗? (精品)

来源:C++ Style and Technique FAQ 作者:Bjarne Stroustrup 翻译:紫云英

 

Q: 我可以写"void main()"吗?
A: 这样的定义
    void main() { /* ... */ }
 
不是C++,也不是C。(参见ISO C++ 标准 3.6.1[2] 或 ISO C 标准 5.1.2.2.1) 一个遵从标准的编译器实作应该接受
    int main() { /* ... */ }

    int main(int argc, char* argv[]) { /* ... */ }
 
编译器也可以提供main()的更多重载版本,不过它们都必须返回int,这个int是返回给你的程序的调用者的,这是种“负责”的做法,“什么都不返回”可不大好哦。如果你程序的调用者不支持用“返回值”来交流,这个值会被自动忽略——但这也不能使void main()成为合法的C++或C代码。即使你的编译器支持这种定义,最好也不要养成这种习惯——否则你可能被其他C/C++程序员认为浅薄无知哦。
 
在C++中,如果你嫌麻烦,可以不必显式地写出return语句。编译器会自动返回0。例如:
    #include<iostream>

    int main()
    {
        std::cout << "This program returns the integer value 0/n";
    }
 
麻烦吗?不麻烦,int main()比void main()还少了一个字母呢 :O)另外,还要请你注意:无论是ISO C++还是C99都不允许你省略返回类型。这也就是说,和C89及ARM C++[译注:指Margaret Ellis和Bjarne Stroustrup于1990年合著的《The Annotated C++ Reference Manual》中描述的C++]不同,int并不是缺省返回值类型。所以,
    #include<iostream>

    main() { /* ... */ }
会出错,因为main()函数缺少返回类型。

 

英文原文: http://www2.research.att.com/~bs/bs_faq2.html#void-main

强烈推荐: Bjarne Stroustrup's C++ Style and Technique FAQ (英文)

 

转载声明: 本文转自 http://stdcpp.cn/html/24/26/0611/176.htm (蚂蚁C/C++)

=========================================================================

 

void main(void) - the Wrong Thing

 

The newsgroup, comp.lang.c, is plagued by an almost continuous discussion of whether we can or cannot use void as a return type for main. The ANSI standard says "no", which should be an end of it. However, a number of beginners' books on C have used void main(void) in all of their examples, leading to a huge number of people who don't know any better.

When people ask why using a void is wrong, (since it seems to work), the answer is usually one of the following:
Because the standard says so.
(To which the answer is usually of the form "but it works for me!")
Because the startup routines that call main could be assuming that the return value will be pushed onto the stack. If main() does not do this, then this could lead to stack corruption in the program's exit sequence, and cause it to crash.
(To which the answer is usually of the form "but it works for me!")
Because you are likely to return a random value to the invokation environment. This is bad, because if someone wants to check whether your program failed, or to call your program from a makefile, then they won't be able to guarantee that a non-zero return code implies failure.
(To which the answer is usually of the form "that's their problem").

This page demonstrates a system on which a void main(void) program will very likely cause problems in the third class above. Calling the program from a script may cause the script to die, whether or not its return code is checked. Calling it from a makefile may cause make to complain. Calling it from the command line may cause an error to be reported.

RISC OS is the native operating system of Acorn's range of ARM based computers. One of the facilities of this OS is a system variable, Sys$RCLimit. The value of this variable specifies the maximum value that a program may return to the OS without causing RISC OS itself to raise an error. The default value of this variable is set by the OS at 256. I'm not too sure what the intended function of this variable was, but it exists, and that's that.

Now, let's look at an example program using int main(void).
int main(void)
{
    return 42;
}
Compiling it to ARM assembly language, using gcc (as an aside: Acorn's own C compiler reports a warning with void main(void) and converts it to an integer function returning zero) gives the following:
|main|:
        mov     ip, sp 
        stmfd   sp!, {rfp, fp, ip, lr, pc}
        sub     fp, ip, #4
        cmps    sp,sl
        bllt    |x$stack_overflow|
        bl      |___main|

        mov     r0, #42
        ldmdb   fp, {rfp, fp, sp, pc}^

The first six instructions are initialisation and stack checking. The final two return 42 to the library startup code. So, the return value of main is passed in R0. Note that the library startup code is expecting to call a function returning an integer, so will happily use the value returned in R0.

What happens with a void main function? Well, here's an example.
#include <stdio.h>

char buf[1024];
void main(void)
{
    (void)fgets(buf, 1024, stdin);
}
The program waits for a line of text from its standard input, nothing else. Again we compile it to assembler:
|.LC0|:
        dcd     |__iob|
|.LC1|:
        dcd     |buf|
|main|:
        mov     ip, sp 
        stmfd   sp!, {rfp, fp, ip, lr, pc}
        sub     fp, ip, #4
        cmps    sp,sl
        bllt    |x$stack_overflow|
        bl      |___main|

        ldr     r2, [pc, #|.LC0| - . - 8]
        mov     r1, #1024
        ldr     r0, [pc, #|.LC1| - . - 8]

        bl      |fgets|

        ldmdb   fp, {rfp, fp, sp, pc}^

        area    |buf|, DATA, COMMON, NOINIT
        %       1024

Again, the first six instructions in main set things up. The next three set up the arguments for the call to fgets. Then we call fgets and return to the caller. stdio.h says that fgets returns a pointer to the buffer. So, in this instance, what we are returning to the library startup code is a pointer to buf. Under RISC OS, all C programs are mapped into memory at 0x8000. So, we will be returning a value to the OS which is > 32768 (hence, certainly > the default value of Sys$RCLimit). The OS then raises an error.

Here's the result of compiling and running the program:
SCSI: void % gcc void.c -o void
Drlink AOF Linker  Version 0.28  30/07/95
SCSI: void % show Sys$RCLimit
Sys$RCLimit : 256
SCSI: void % void
I enter this line
Return code too large
SCSI: void %

And, in a script file:
SCSI: void % cat script

void
echo Finished

SCSI: void % run script
I enter this line
Return code too large
SCSI: void %

The error interrupts the script before the second command is run.

Note that the example above was a little contrived in order to make the final function call return a pointer. A better example where this could cause problems is one where the program uses printf to report a usage string > 256 characters long prior to returning or, worse still, one where the program uses printf to output data depending on user input. Depending on the length of the user's input text, the program may or may not cause an error which is solely due to the use of void as a return type for main.

So, if you want your software to be portable, please make main return int. It does matter.

 

 

转载声明: 本文转自 http://users.aber.ac.uk/auj/voidmain.shtml

=========================================================================

 

强烈推荐: Bjarne Stroustrup's C++ Style and Technique FAQ (英文)

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "dma.h" #include "tim.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if(huart == &huart2) { RS485_2_RX; // RS485 ?????? memset(usart2_data.rbuff, 0, usart2_data.len);//???????????? HAL_UART_Receive_DMA(&huart2,usart2_data.rbuff,MAX);//?????DMA???? usart2_data.sdflag = 0; //????????????? } } /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_USART1_UART_Init(); MX_USART2_UART_Init(); MX_USART3_UART_Init(); MX_TIM6_Init(); /* USER CODE BEGIN 2 */ RS485_2_TX; HAL_UART_Transmit(&huart1,(uint8_t *)"123456",3,1000); printf("串口\r\n"); HAL_Delay(1); RS485_2_RX;//RS485进入接收模式 Uart1_Config(); Uart2_Config(); Uart3_Config(); //4G // Lte_Check();//确认设备连接 // Close_Heart();//关闭心跳包 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { // HAL_Delay(1500); // HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin); if(Device_Net_State==0) { G4_Connect_Net(); } else if(Device_Net_State==1) { MQTT_Connect(); } // else if(Device_Net_State==2) // { // if(PUBLISH_Period[0]>=PUBLISH_Period[1]) // {//定时器6中断累加,需要初始化 // PUBLISH_Period[0]=0; // MQTT_Publish();//上传数据 // } // } HAL_Delay(1000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file usart.c * @brief This file provides code for the configuration * of the USART instances. ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "usart.h" /* USER CODE BEGIN 0 */ struct usart usart1_data = {0}; struct usart usart2_data = {0}; struct usart usart3_data = {0}; /* USER CODE END 0 */ UART_HandleTypeDef huart1; UART_HandleTypeDef huart2; UART_HandleTypeDef huart3; DMA_HandleTypeDef hdma_usart1_rx; DMA_HandleTypeDef hdma_usart1_tx; DMA_HandleTypeDef hdma_usart2_rx; DMA_HandleTypeDef hdma_usart2_tx; DMA_HandleTypeDef hdma_usart3_rx; DMA_HandleTypeDef hdma_usart3_tx; /* USART1 init function */ void MX_USART1_UART_Init(void) { /* USER CODE BEGIN USART1_Init 0 */ /* USER CODE END USART1_Init 0 */ /* USER CODE BEGIN USART1_Init 1 */ /* USER CODE END USART1_Init 1 */ huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART1_Init 2 */ /* USER CODE END USART1_Init 2 */ } /* USART2 init function */ void MX_USART2_UART_Init(void) { /* USER CODE BEGIN USART2_Init 0 */ /* USER CODE END USART2_Init 0 */ /* USER CODE BEGIN USART2_Init 1 */ /* USER CODE END USART2_Init 1 */ huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART2_Init 2 */ /* USER CODE END USART2_Init 2 */ } /* USART3 init function */ void MX_USART3_UART_Init(void) { /* USER CODE BEGIN USART3_Init 0 */ /* USER CODE END USART3_Init 0 */ /* USER CODE BEGIN USART3_Init 1 */ /* USER CODE END USART3_Init 1 */ huart3.Instance = USART3; huart3.Init.BaudRate = 115200; huart3.Init.WordLength = UART_WORDLENGTH_8B; huart3.Init.StopBits = UART_STOPBITS_1; huart3.Init.Parity = UART_PARITY_NONE; huart3.Init.Mode = UART_MODE_TX_RX; huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart3.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart3) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART3_Init 2 */ /* USER CODE END USART3_Init 2 */ } void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */ /* USART1 clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART1 DMA Init */ /* USART1_RX Init */ hdma_usart1_rx.Instance = DMA1_Channel5; hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_rx.Init.Mode = DMA_NORMAL; hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx); /* USART1_TX Init */ hdma_usart1_tx.Instance = DMA1_Channel4; hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_tx.Init.Mode = DMA_NORMAL; hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx); /* USART1 interrupt Init */ HAL_NVIC_SetPriority(USART1_IRQn, 1, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspInit 1 */ /* USER CODE END USART1_MspInit 1 */ } else if(uartHandle->Instance==USART2) { /* USER CODE BEGIN USART2_MspInit 0 */ /* USER CODE END USART2_MspInit 0 */ /* USART2 clock enable */ __HAL_RCC_USART2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART2 GPIO Configuration PA2 ------> USART2_TX PA3 ------> USART2_RX */ GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART2 DMA Init */ /* USART2_RX Init */ hdma_usart2_rx.Instance = DMA1_Channel6; hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart2_rx.Init.Mode = DMA_NORMAL; hdma_usart2_rx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart2_rx); /* USART2_TX Init */ hdma_usart2_tx.Instance = DMA1_Channel7; hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart2_tx.Init.Mode = DMA_NORMAL; hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart2_tx); /* USART2 interrupt Init */ HAL_NVIC_SetPriority(USART2_IRQn, 3, 0); HAL_NVIC_EnableIRQ(USART2_IRQn); /* USER CODE BEGIN USART2_MspInit 1 */ /* USER CODE END USART2_MspInit 1 */ } else if(uartHandle->Instance==USART3) { /* USER CODE BEGIN USART3_MspInit 0 */ /* USER CODE END USART3_MspInit 0 */ /* USART3 clock enable */ __HAL_RCC_USART3_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /**USART3 GPIO Configuration PB10 ------> USART3_TX PB11 ------> USART3_RX */ GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* USART3 DMA Init */ /* USART3_RX Init */ hdma_usart3_rx.Instance = DMA1_Channel3; hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart3_rx.Init.Mode = DMA_NORMAL; hdma_usart3_rx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart3_rx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart3_rx); /* USART3_TX Init */ hdma_usart3_tx.Instance = DMA1_Channel2; hdma_usart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart3_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart3_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart3_tx.Init.Mode = DMA_NORMAL; hdma_usart3_tx.Init.Priority = DMA_PRIORITY_LOW; if (HAL_DMA_Init(&hdma_usart3_tx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart3_tx); /* USART3 interrupt Init */ HAL_NVIC_SetPriority(USART3_IRQn, 2, 0); HAL_NVIC_EnableIRQ(USART3_IRQn); /* USER CODE BEGIN USART3_MspInit 1 */ /* USER CODE END USART3_MspInit 1 */ } } void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle) { if(uartHandle->Instance==USART1) { /* USER CODE BEGIN USART1_MspDeInit 0 */ /* USER CODE END USART1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_USART1_CLK_DISABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10); /* USART1 DMA DeInit */ HAL_DMA_DeInit(uartHandle->hdmarx); HAL_DMA_DeInit(uartHandle->hdmatx); /* USART1 interrupt Deinit */ HAL_NVIC_DisableIRQ(USART1_IRQn); /* USER CODE BEGIN USART1_MspDeInit 1 */ /* USER CODE END USART1_MspDeInit 1 */ } else if(uartHandle->Instance==USART2) { /* USER CODE BEGIN USART2_MspDeInit 0 */ /* USER CODE END USART2_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_USART2_CLK_DISABLE(); /**USART2 GPIO Configuration PA2 ------> USART2_TX PA3 ------> USART2_RX */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3); /* USART2 DMA DeInit */ HAL_DMA_DeInit(uartHandle->hdmarx); HAL_DMA_DeInit(uartHandle->hdmatx); /* USART2 interrupt Deinit */ HAL_NVIC_DisableIRQ(USART2_IRQn); /* USER CODE BEGIN USART2_MspDeInit 1 */ /* USER CODE END USART2_MspDeInit 1 */ } else if(uartHandle->Instance==USART3) { /* USER CODE BEGIN USART3_MspDeInit 0 */ /* USER CODE END USART3_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_USART3_CLK_DISABLE(); /**USART3 GPIO Configuration PB10 ------> USART3_TX PB11 ------> USART3_RX */ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11); /* USART3 DMA DeInit */ HAL_DMA_DeInit(uartHandle->hdmarx); HAL_DMA_DeInit(uartHandle->hdmatx); /* USART3 interrupt Deinit */ HAL_NVIC_DisableIRQ(USART3_IRQn); /* USER CODE BEGIN USART3_MspDeInit 1 */ /* USER CODE END USART3_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ //重定向printf int fputc(int c,FILE *f) { HAL_UART_Transmit(&huart1,(uint8_t *)&c,1,1000); return c; } void Uart1_Config(void) { HAL_UART_Receive_DMA(&huart1, usart1_data.rbuff, MAX);//����DMA���գ������ݱ�����usart1_data.buff�У�MAXΪ1024 __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//使能串口1空闲中断 } void Uart2_Config(void) { HAL_UART_Receive_DMA(&huart2, usart2_data.rbuff, MAX);//����DMA���գ������ݱ�����usart1_data.buff�У�MAXΪ1024 __HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);//使能串口2空闲中断 } void Uart3_Config(void) { HAL_UART_Receive_DMA(&huart3, usart3_data.rbuff, MAX);//����DMA���գ������ݱ�����usart1_data.buff�У�MAXΪ1024 __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);//使能串口3空闲中断 } //函数名称:void RS485_Usart3_DMA_Send(uint8_t *buf,uint8_t len) //功能描述:串口2采用RS485总线实现DMA发送 //参数说明:*buf 数据帧的指针,len数据帧的长度 void RS485_Usart2_DMA_Send(uint8_t *buf,uint8_t len) { uint8_t i; if(usart2_data.sdflag==0) //如果串口发送处于完成状态 { RS485_2_TX; //发送控制置位到发送状态——使能高电平正在发送 usart2_data.sdflag=1; //发送完成标识置位———有发送 for( i=0;i<10;i++); //短暂延时,使EN进入高电平稳定状态 if(HAL_UART_Transmit_DMA(&huart2, buf,len)!= HAL_OK) //判断是否发送正常,如果出现异常则进入异常中断函数 { Error_Handler(); } } } /* USER CODE END 1 */ /* USER CODE BEGIN Header */ /** ****************************************************************************** * @file stm32f1xx_it.c * @brief Interrupt Service Routines. ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f1xx_it.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "usart.h" #include "string.h" #include "tim.h" #include "4G.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN TD */ /* USER CODE END TD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /* External variables --------------------------------------------------------*/ extern TIM_HandleTypeDef htim6; extern DMA_HandleTypeDef hdma_usart1_rx; extern DMA_HandleTypeDef hdma_usart1_tx; extern DMA_HandleTypeDef hdma_usart2_rx; extern DMA_HandleTypeDef hdma_usart2_tx; extern DMA_HandleTypeDef hdma_usart3_rx; extern DMA_HandleTypeDef hdma_usart3_tx; extern UART_HandleTypeDef huart1; extern UART_HandleTypeDef huart2; extern UART_HandleTypeDef huart3; /* USER CODE BEGIN EV */ /* USER CODE END EV */ /******************************************************************************/ /* Cortex-M3 Processor Interruption and Exception Handlers */ /******************************************************************************/ /** * @brief This function handles Non maskable interrupt. */ void NMI_Handler(void) { /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ /* USER CODE END NonMaskableInt_IRQn 0 */ /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ while (1) { } /* USER CODE END NonMaskableInt_IRQn 1 */ } /** * @brief This function handles Hard fault interrupt. */ void HardFault_Handler(void) { /* USER CODE BEGIN HardFault_IRQn 0 */ /* USER CODE END HardFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_HardFault_IRQn 0 */ /* USER CODE END W1_HardFault_IRQn 0 */ } } /** * @brief This function handles Memory management fault. */ void MemManage_Handler(void) { /* USER CODE BEGIN MemoryManagement_IRQn 0 */ /* USER CODE END MemoryManagement_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ /* USER CODE END W1_MemoryManagement_IRQn 0 */ } } /** * @brief This function handles Prefetch fault, memory access fault. */ void BusFault_Handler(void) { /* USER CODE BEGIN BusFault_IRQn 0 */ /* USER CODE END BusFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_BusFault_IRQn 0 */ /* USER CODE END W1_BusFault_IRQn 0 */ } } /** * @brief This function handles Undefined instruction or illegal state. */ void UsageFault_Handler(void) { /* USER CODE BEGIN UsageFault_IRQn 0 */ /* USER CODE END UsageFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ /* USER CODE END W1_UsageFault_IRQn 0 */ } } /** * @brief This function handles System service call via SWI instruction. */ void SVC_Handler(void) { /* USER CODE BEGIN SVCall_IRQn 0 */ /* USER CODE END SVCall_IRQn 0 */ /* USER CODE BEGIN SVCall_IRQn 1 */ /* USER CODE END SVCall_IRQn 1 */ } /** * @brief This function handles Debug monitor. */ void DebugMon_Handler(void) { /* USER CODE BEGIN DebugMonitor_IRQn 0 */ /* USER CODE END DebugMonitor_IRQn 0 */ /* USER CODE BEGIN DebugMonitor_IRQn 1 */ /* USER CODE END DebugMonitor_IRQn 1 */ } /** * @brief This function handles Pendable request for system service. */ void PendSV_Handler(void) { /* USER CODE BEGIN PendSV_IRQn 0 */ /* USER CODE END PendSV_IRQn 0 */ /* USER CODE BEGIN PendSV_IRQn 1 */ /* USER CODE END PendSV_IRQn 1 */ } /** * @brief This function handles System tick timer. */ void SysTick_Handler(void) { /* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); /* USER CODE BEGIN SysTick_IRQn 1 */ /* USER CODE END SysTick_IRQn 1 */ } /******************************************************************************/ /* STM32F1xx Peripheral Interrupt Handlers */ /* Add here the Interrupt Handlers for the used peripherals. */ /* For the available peripheral interrupt handler names, */ /* please refer to the startup file (startup_stm32f1xx.s). */ /******************************************************************************/ /** * @brief This function handles DMA1 channel2 global interrupt. */ void DMA1_Channel2_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel2_IRQn 0 */ /* USER CODE END DMA1_Channel2_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_usart3_tx); /* USER CODE BEGIN DMA1_Channel2_IRQn 1 */ /* USER CODE END DMA1_Channel2_IRQn 1 */ } /** * @brief This function handles DMA1 channel3 global interrupt. */ void DMA1_Channel3_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel3_IRQn 0 */ /* USER CODE END DMA1_Channel3_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_usart3_rx); /* USER CODE BEGIN DMA1_Channel3_IRQn 1 */ /* USER CODE END DMA1_Channel3_IRQn 1 */ } /** * @brief This function handles DMA1 channel4 global interrupt. */ void DMA1_Channel4_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel4_IRQn 0 */ /* USER CODE END DMA1_Channel4_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_usart1_tx); /* USER CODE BEGIN DMA1_Channel4_IRQn 1 */ /* USER CODE END DMA1_Channel4_IRQn 1 */ } /** * @brief This function handles DMA1 channel5 global interrupt. */ void DMA1_Channel5_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel5_IRQn 0 */ /* USER CODE END DMA1_Channel5_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_usart1_rx); /* USER CODE BEGIN DMA1_Channel5_IRQn 1 */ /* USER CODE END DMA1_Channel5_IRQn 1 */ } /** * @brief This function handles DMA1 channel6 global interrupt. */ void DMA1_Channel6_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel6_IRQn 0 */ /* USER CODE END DMA1_Channel6_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_usart2_rx); /* USER CODE BEGIN DMA1_Channel6_IRQn 1 */ /* USER CODE END DMA1_Channel6_IRQn 1 */ } /** * @brief This function handles DMA1 channel7 global interrupt. */ void DMA1_Channel7_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel7_IRQn 0 */ /* USER CODE END DMA1_Channel7_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_usart2_tx); /* USER CODE BEGIN DMA1_Channel7_IRQn 1 */ /* USER CODE END DMA1_Channel7_IRQn 1 */ } /** * @brief This function handles USART1 global interrupt. */ void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ //�жϿ��б�־λ�Ƿ���λ if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) { __HAL_UART_CLEAR_IDLEFLAG(&huart1);//��������жϱ�־λ HAL_UART_DMAStop(&huart1);//ֹͣDMA�������� usart1_data.len = MAX - __HAL_DMA_GET_COUNTER(huart1.hdmarx);//����˴ν��յ������ݳ��� usart1_data.rdflag = 1;//���ý�����ɱ�־ // #if debug //�����ã����Խ��յ�������ת����ȥ������һ������֮�������¿���DMA���� if(usart1_data.rdflag == 1 && usart3_data.sdflag == 0) { // printf("USART1接收: %s\n", usart1_data.rbuff); // HAL_UART_Transmit_DMA(&huart1,usart1_data.rbuff,usart1_data.len); usart3_data.sdflag = 1; if(HAL_UART_Transmit(&huart3,usart1_data.rbuff,usart1_data.len,100) != HAL_OK) { printf("USART3发送失败\n"); // 调试打印 } memset(usart1_data.rbuff, 0, usart1_data.len); usart1_data.rdflag = 0; usart3_data.sdflag = 0; HAL_UART_Receive_DMA(&huart1, usart1_data.rbuff, MAX); } // #endif } /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ /* USER CODE END USART1_IRQn 1 */ } /** * @brief This function handles USART2 global interrupt. */ void USART2_IRQHandler(void) { /* USER CODE BEGIN USART2_IRQn 0 */ uint32_t tmp_flag = 0; uint32_t temp; tmp_flag =__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE); //获取IDLE标志位 if((tmp_flag != RESET)) //idle标志被置位 { __HAL_UART_CLEAR_IDLEFLAG(&huart2); //清除标志位 HAL_UART_DMAStop(&huart2); //停止DMA传输,防止串行总线其他帧的干扰 temp = __HAL_DMA_GET_COUNTER(&hdma_usart2_rx); //获取DMA中未传输的数据个数 usart2_data.len = MAX - temp; //总计数减去未传输的数据个数,得到实际接收的数据个数 usart2_data.rdflag = 1; // 接收完成标志位置1 //如果是从设备,此处可以用条件语句判断是否应该应答主机的呼叫(从设备地址与呼叫地址一致),如果是就发送(应答)。下面是直接发送收到的信息 RS485_Usart2_DMA_Send(usart2_data.rbuff,usart2_data.len); //RS485发送数据 usart2_data.rdflag = 0; // 接收完成标志位置0 //下面的语句通常在回调函数内调用,在此处调用也可以 //HAL_UART_Receive_DMA(&huart2,usart2_data.rbuff,MAX);//重新打开DMA接收 } /* USER CODE END USART2_IRQn 0 */ HAL_UART_IRQHandler(&huart2); /* USER CODE BEGIN USART2_IRQn 1 */ /* USER CODE END USART2_IRQn 1 */ } /** * @brief This function handles USART3 global interrupt. */ void USART3_IRQHandler(void) { /* USER CODE BEGIN USART3_IRQn 0 */ // printf("USART3中断触发\n"); // 新增:打印中断触发提示 if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET) { // printf("USART3检测到空闲中断\n"); // 新增:确认IDLE标志触发 __HAL_UART_CLEAR_IDLEFLAG(&huart3);//��������жϱ�־λ HAL_UART_DMAStop(&huart3);//ֹͣDMA�������� usart3_data.len = MAX - __HAL_DMA_GET_COUNTER(huart3.hdmarx);//����˴ν��յ������ݳ��� usart3_data.rdflag = 1;//���ý�����ɱ�־ // #if debug //�����ã����Խ��յ�������ת����ȥ������һ������֮�������¿���DMA���� if(usart3_data.rdflag == 1) { // printf("4G:%s\n",usart3_data.rbuff); HAL_UART_Transmit(&huart1,usart3_data.rbuff,usart3_data.len,100); memcpy(G4.R_Buff,usart3_data.rbuff,usart3_data.len); G4.R_Cont = usart3_data.len; memset(usart3_data.rbuff, 0, usart3_data.len); usart3_data.rdflag = 0; HAL_UART_Receive_DMA(&huart3, usart3_data.rbuff, MAX); } // #endif } /* USER CODE END USART3_IRQn 0 */ HAL_UART_IRQHandler(&huart3); /* USER CODE BEGIN USART3_IRQn 1 */ /* USER CODE END USART3_IRQn 1 */ } /** * @brief This function handles TIM6 global interrupt. */ void TIM6_IRQHandler(void) { /* USER CODE BEGIN TIM6_IRQn 0 */ //在此写状态机的计时 //1.判断中断是否发生 if((TIM6->SR & (0x01<<0))!=0) { //2.执行中断服务函数内容 PUBLISH_Period[0]++; //3.清除中断标志位 TIM6->SR &= ~(0x01<<0); } /* USER CODE END TIM6_IRQn 0 */ HAL_TIM_IRQHandler(&htim6); /* USER CODE BEGIN TIM6_IRQn 1 */ /* USER CODE END TIM6_IRQn 1 */ } /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ #include "4G.h" struct WH_LTE_7S1 G4; uint8_t Connect_Step; uint8_t Device_Net_State; //单字节发送函数 void SendByte(uint8_t data) { HAL_UART_Transmit(&huart3,&data,1,1000); } //发送字符串 //参数 字符串的首地址 void SendStr(uint8_t *Str) { while(*Str != '\0') {//*Str++ (1)先算*Str (2)再算Str++ SendByte(*Str++); } } //发送数组 //参数1 数组的首地址 //参数2 数组的长度 void SendBuff(uint8_t *Buff , uint16_t Length) { for(uint16_t i=0;i<Length;i++) { SendByte(Buff[i]); //两种发送都可以 // ESP_SendByte(*Buff++); } } //清除接收缓冲区 void R_BUFF_CLEAR(void) { memset(G4.R_Buff,0,sizeof(G4.R_Buff)); G4.R_Cont=0; } //确认设备连接 //uint8_t Lte_Check(void) //{ // if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT\r\nOK",(uint8_t *)"usr.cn#\r\nOK",G4.R_Buff,500,1)) // { // printf("%d\n",G4.R_Cont); // printf("%s",G4.R_Buff); // printf("4G module is functioning properly. \n"); // return 1; // } // return 0; //} //关闭心跳包 //uint8_t Close_Heart(void) //{ // if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT+HEARTEN=OFF\r\nOK",(uint8_t *)"usr.cn#\r\nOK",G4.R_Buff,500,1)) // { // return 1; // } // return 0; //} //链接服务器 uint8_t SetSeverInfomation(uint8_t *SeverIP,uint16_t SeverPORT) { char buff[128] = {0}; printf("SeverIP:%s \r\nSeverPort:%d\r\n",SeverIP,SeverPORT); sprintf(buff,"usr.cn#AT+SOCKA=TCP,%s,%d\r\n",SeverIP,SeverPORT); if(SendCMD_CheckRES((uint8_t *)buff,(uint8_t *)"usr.cn#\r\nOK",G4.R_Buff,1000,1)) { return 1; } return 0; } //重启4G模块使配置生效 //uint8_t RestartLte(void) //{ // if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT+S\r\nOK",(uint8_t *)"usr.cn#\r\nOK",G4.R_Buff,10000,1)) // { // return 1; // } // return 0; //} void G4_Connect_Net(void) { switch(Connect_Step) { case 0://确认设备连接 printf("1、测试设备\n"); if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT\r\nOK",(uint8_t *)"usr.cn#\r\nOK",G4.R_Buff,500,1)==1) Connect_Step++; break; case 1://关闭心跳包 printf("2、关闭心跳\n"); if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT+HEARTEN=OFF\r\nOK",(uint8_t *)"usr.cn#\r\nOK",G4.R_Buff,500,1)==1) Connect_Step++; break; case 2: printf("3、退出套接字\r\n"); if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT+SDPEN=OFF\r\n",(uint8_t *)"OK",G4.R_Buff,100,1)==1) Connect_Step++; break; case 3: printf("4、退出注册\r\n"); if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT+REGEN=OFF\r\n",(uint8_t *)"OK",G4.R_Buff,100,1)==1) Connect_Step++; break; case 4: printf("5、同步NTP服务器\r\n"); if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT+NTPEN=ON\r\n",(uint8_t *)"OK",G4.R_Buff,10000,1)==1) Connect_Step++; break; case 5: printf("6、设置时间60s\r\n"); if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT+NTPTM=60\r\n",(uint8_t *)"OK",G4.R_Buff,10000,1)==1) Connect_Step++; break; case 6://链接服务器 printf("7、链接华为云\n"); if(SetSeverInfomation((uint8_t *)HostName,PORT)==1) Connect_Step++; break; case 7://重启4G模块使配置生效 printf("8、重启模块使能配置\n"); if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT+S\r\nOK",(uint8_t *)"usr.cn#\r\nOK",G4.R_Buff,10000,1) ==1) Connect_Step++; break; case 8: printf("9、查看已链接服务器\n"); if(SendCMD_CheckRES((uint8_t *)"usr.cn#AT+SOCKALK\r\n",(uint8_t *)"Connected",G4.R_Buff,1000,1) == 1) { Connect_Step=0; // Connect_Step++; Device_Net_State=1; //设备网络状态置1 } break; case 9: // HAL_Delay(500); // MQTT_Connect(); // Connect_Step=0; //联网步骤清0 // HAL_Delay(1000); break; } } //检测发送AT指令后,是否正确回复 /* 参数1 要发送的命令 参数2 期望的回复 参数3 接收缓冲区 参数4 超时时间 单位:ms 参数5 是否需要检测回复 1需要检测回复 0不需要检测回复 返回值:1 查找成功 0 查找失败 */ uint8_t SendCMD_CheckRES(uint8_t *cmd,uint8_t *res,uint8_t *buff,uint16_t timeout,uint8_t check_flag) { //1.清除接收缓冲区,让接收到数据从头接受 R_BUFF_CLEAR(); //2.发送指定的AT指令 SendStr(cmd); //3.判断是否需要检测回复 if(check_flag==0) {//不需要检测回复 HAL_Delay(timeout); return 1; } while(strstr((char *)buff,(char *)res)==NULL) {//未查找到期望的回复 HAL_Delay(1); timeout--; if(timeout==0) {//超过等待的时间还未等到,返回查找失败 return 0; } } //查找到期望的回复 return 1; } /* strcmp 两个字符串完全相同 strstr 母串中查找子串 */ #include "ali.h" uint8_t LEDSwitch_State=0; uint8_t Connect_flag = 0; //打包连接报文并发送 //注意:连接报文只发送1次 void MQTT_Connect(void) { MQTTPacket_connectData data = MQTTPacket_connectData_initializer; int len = 0; data.clientID.cstring = ClientID; //客户端ID data.keepAliveInterval = 100; //保持连接时间 超过1.5*60的时间未上报数据,平台显示离线 96页手册图例3.5 data.cleansession = 1; //是否清理会话 图例 3.4的位1 data.username.cstring = Username; //用户名 data.password.cstring = Password; //密码 //参数1 打包之后数据存放的缓冲区 //参数2 该缓冲区的大小,避免数组越界 //参数3 连接报文相关的参数 //返回值 成功 打包之后的有效长度 失败 -1 len = MQTTSerialize_connect(G4.S_Buff, Buff_Length, &data); if(len<=0) { printf("连接报文打包失败\r\n"); } printf("拼接connect连接报文成功 报文长度:%d\r\n",len); if(Connect_flag == 0) { R_BUFF_CLEAR(); //发送之前清除一下接收缓冲区 HAL_UART_Transmit(&huart1,G4.S_Buff,len,1000);//只是为了调试使用,通过串口1查看要发送给串口3的数据 HAL_UART_Transmit(&huart3,G4.S_Buff,len,1000); //通过串口3发送函数,将数据发送给4G模块 Connect_flag = 1; } HAL_Delay(5000); printf("\r\n接收到的数据为%s\r\n",G4.R_Buff); if(G4.R_Buff[0]==0x20&&G4.R_Buff[1]==0x02&&G4.R_Buff[2]==0x00&&G4.R_Buff[3]==0x00) {//20 02 00 00是正确的连接应答 Device_Net_State=2; //设备的网络状态修改 printf("连接报文应答成功\r\n"); } else { printf("连接报文应答失败\r\n"); R_BUFF_CLEAR(); } } //{"id":1735270458995,"params":{"temperature":11,"Humidity":22,"LEDSwitch":0,"TemperatureThreshold":33,"LightLux":44,"Smoke_Value":55},"version":"1.0","method":"thing.event.property.post"} //打包发布报文并发送 void MQTT_Publish(void) { MQTTString topicString = MQTTString_initializer; topicString.cstring = Publish_Topic; int len=0; char payload[300] ={0}; //更改下面的格式一定要注意是否符合JSON格式 //需要改 snprintf(payload,sizeof(payload), "{\"services\":[{\"properties\":{\"temp\":%d},\"service_id\":\"dtu\",\"event_time\":null}]}" ,26); int payloadlen = strlen(payload); //strlen是字符串的长度 sizeof数组的长度 //参数1 打包之后数据存放的缓冲区 //参数2 该缓冲区的大小,避免数组越界 //参数3 DUP QOS==0的话,DUP必须是0 //参数4 QOS /*Qos选择0 0 1 2 2最靠谱*/ //参数5 Retained 填0 1 保留该消息,作为问候消息 0不需要保留该消息 //参数6 报文标识符 Qos==0 无报文标识符 //参数7 主题名 //参数8 有效载荷的数组首地址 //参数9 有效载荷的长度 //返回值 成功 打包之后的有效长度 失败 -1 /sys/a1P0lkJ9Jw0/Device_202/thing/event/property/post len = MQTTSerialize_publish(G4.S_Buff, Buff_Length, 0, 0, 0, 0, topicString, (unsigned char*)payload, payloadlen); if(len<=0) { printf("发布报文打包失败\r\n"); } R_BUFF_CLEAR(); //发送之前清除一下接收缓冲区 HAL_UART_Transmit(&huart1,G4.S_Buff,len,1000); //只是为了调试使用,通过串口1查看要发送给串口3的数据 SendBuff(G4.S_Buff,len); //通过串口3发送函数,将数据发送给4G模块 } //订阅下发主题 void MQTT_Subscribe(void) { int msgid = 1; int req_qos = 0; int len = 0; MQTTString topicString = MQTTString_initializer; topicString.cstring = Subcribe_Topic; //参数1 打包之后数据存放的缓冲区 //参数2 该缓冲区的大小,避免数组越界 //参数3 DUP QOS==0的话,DUP必须是0 //参数4 报文标识符 Qos==0 无报文标识符,参数随便给 //参数5 订阅的主题数量 可以支持1次订阅多个主题 //参数6 待订阅的主题 //参数7 主题的消息质量等级 //返回值 成功 打包之后的有效长度 失败 -1 len = MQTTSerialize_subscribe(G4.S_Buff, Buff_Length, 0, msgid, 1, &topicString, &req_qos); if(len<=0) { printf("订阅报文打包失败\r\n"); } R_BUFF_CLEAR(); //发送之前清除一下接收缓冲区 HAL_UART_Transmit(&huart1,G4.S_Buff,len,1000); //只是为了调试使用,通过串口1查看要发送给串口3的数据 SendBuff(G4.S_Buff,len); //通过串口3发送函数,将数据发送给4G模块 // Delay_ms(1000); HAL_Delay(1000); if(G4.R_Buff[0]==0x90) {//是正确的订阅应答 90 03 00 01 01 Device_Net_State=3; //设备的网络状态修改 printf("订阅报文应答成功\r\n"); } else { printf("订阅报文应答失败\r\n"); } } //发送心跳 void MQTT_Ping(void) { int len = 0; //参数1 打包之后数据存放的缓冲区 //参数2 该缓冲区的大小,避免数组越界 //返回值 成功 打包之后的有效长度 失败 -1 len=MQTTSerialize_pingreq(G4.S_Buff, Buff_Length); if(len<=0) { printf("心跳报文打包失败\r\n"); } R_BUFF_CLEAR(); //发送之前清除一下接收缓冲区 HAL_UART_Transmit(&huart1,G4.S_Buff,len,1000); //只是为了调试使用,通过串口1查看要发送给串口3的数据 SendBuff(G4.S_Buff,len); //通过串口3发送函数,将数据发送给4G模块 } 为何在发送连接报文后,收不到服务器返回的连接报文应答
最新发布
08-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值