[STM32F4] 基于STM32(串口+DMA+空闲中断+环形缓冲区)实现 YMODEM协议IAP在线烧写程序

[复制链接]
 楼主| zero949079783 发表于 2024-4-21 16:01 | 显示全部楼层 |阅读模式
本帖最后由 zero949079783 于 2024-7-14 10:27 编辑

基于STM32(串口+DMA+空闲中断+环形缓冲区)实现 YMODEM协议IAP在线烧写程序
BootLoader 扇区: 0x08000000  - 0x08004000 共16K大小

生成BIN: fromelf.exe --bin -o "$L@L.bin" "#L

上位机软件:SecureCRT

371096624ce7eeb687.png

Ymodem_STM32F1:
链接:https://pan.baidu.com/s/1SO34uS3flsdE8MdL4HHU0g?pwd=802v
提取码:802v
Ymodem_STM32F4:
链接:https://pan.baidu.com/s/13Kh6QzgNosYnYE5fJ-TB4Q?pwd=u5tj
提取码:u5tj
https://gitee.com/csx949089783/ymodem_-stm32-f4.git









YMODED接口函数:
  1. #include "ymodem.h"
  2. #include "crc.h"
  3. #include "usart.h"
  4. #include "inner_flash.h"
  5. #include "delay.h"
  6. #include "key.h"
  7. #define YMODEM_TIME 10


  8. typedef  void (*pFunction)(void);
  9. pFunction Jump_To_Application;


  10. typedef struct{
  11.         uint8_t OTA_FLAG :          1;
  12.         uint8_t YMODE_FLAG : 1;
  13.         uint8_t YMODE_Frist_FLAG :1;
  14.         uint8_t YMODE_Frist_Pack_FLAG: 1;
  15.         uint8_t YMODE_EOH_STX_DATALEN_FLAG :1;               
  16.         uint8_t fileName[256];                                                                                //文件名        
  17.         uint8_t  UpdataBuffer[STM32_PAGE_SIZE];                //接收数据缓冲区        
  18.         uint16_t time;                                                                                                                                        //OTA退出时间
  19.         uint16_t count;                                                        
  20.         uint32_t num;                                                                                                                        //接收数据包数
  21.         uint32_t STXnum;                                                                                                        //接收数据包数               
  22.         uint32_t crc;                                                                                                                        //CRC校验
  23.         uint32_t remanider;                                                                                                //数据余数
  24.         uint32_t packnum;                                                                                                        //数据总包数
  25.         uint32_t remaniderpacknum;                                                                //数据余数总包数(1024时)
  26.         uint32_t fileSize;                                                                                                //文件大小
  27.         uint32_t JumpAddress;                                                                                        //APP跳转地址
  28. }YMODEM_T ;

  29. YMODEM_T ymodem_t;

  30. void Ymodem_Init(void)
  31. {
  32.         memset(&ymodem_t,0,sizeof(ymodem_t));
  33.         ymodem_t.time = YMODEM_TIME;
  34. }


  35. static void BootLoader_To_App(void)
  36. {
  37.         Delay_ms(1);
  38.         printf("\r\n");
  39.         printf("BootLoader_To_App.....\r\n");
  40.         Delay_ms(1);
  41.         FLASH_Lock();
  42.         
  43.         SysTick->CTRL &= SysTick_CTRL_TICKINT_Msk;        //关滴答定时器
  44.         
  45.   ymodem_t.JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);        
  46.   /* Jump to user application */
  47.   Jump_To_Application = (pFunction) ymodem_t.JumpAddress;
  48.   /* Initialize user application's Stack Pointer */
  49.   __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
  50.   Jump_To_Application();
  51. }

  52. static void BootLoader_SendByte(uint8_t data)
  53. {
  54.         Usartx_SendArray(USART1,&data,1);
  55. }

  56. /*************************************************************************
  57. *        函 数 名: BootLoader_EraseFlash
  58. *        功能说明: Flash扇区擦除
  59. *        形    参:startSectorAddr:起始扇区地址    numSector:扇区个数
  60. *        返 回 值: 无
  61. **************************************************************************/
  62. void BootLoader_EraseFlash(void)
  63. {
  64.         STM32_EraseFlash(STM32_A_SADDR,11);
  65. }

  66. /*************************************************************************
  67. *        函 数 名: BootLoader_WriteFlash
  68. *        功能说明: 数据写入
  69. *        形    参:startAddr:起始地址   writeData:写入数据   numByte:写入字节数
  70. *        返 回 值: 无
  71. **************************************************************************/
  72. static void BootLoader_WriteFlash(uint32_t startAddr, uint32_t* writeData, uint32_t numByte)
  73. {
  74.         STM32_WriteFlash(startAddr,writeData,numByte);
  75. }



  76. void BootLoader_Meun(void)
  77. {
  78.         static uint16_t times = 0;
  79.         times ++;

  80.          if(ymodem_t.OTA_FLAG == YMODEM_DISABLE && times%1000 == 0)
  81.                 {               
  82.                         ymodem_t.time --;
  83.                         
  84.                         printf(" \r\n %ds后退出BootLoader\r\n ",ymodem_t.time);
  85.                         if(ymodem_t.time <= 0)
  86.                         {
  87.                                 BootLoader_To_App();
  88.                         }
  89.                 }
  90.                 else if(ymodem_t.YMODE_FLAG == YMODEMD_ENABLE && times %500 == 0)
  91.                 {
  92.                         ymodem_t.time = YMODEM_TIME;
  93.                         BootLoader_SendByte(CA);        //发送握手
  94.                 }

  95.         //按键双击进入OTA
  96.         if( get_Key_Val() == 0x51 && ymodem_t.YMODE_FLAG == YMODEM_DISABLE && ymodem_t.OTA_FLAG == YMODEM_DISABLE)
  97.         {        
  98.                         printf("EraseFlash......\r\n");
  99.                         BootLoader_EraseFlash();
  100.                         printf("EraseFlash successfully \r\n");
  101.                         ymodem_t.OTA_FLAG = 1;
  102.                         ymodem_t.YMODE_FLAG = 1;
  103.         }


  104. }

  105. static void BootLoader_Com(uint8_t *data)
  106. {
  107.         if(memcmp(data,"1",1)==0 )        //当接收到上位机或者双击时,进入OTA
  108.         {
  109.                         printf("EraseFlash......\r\n");
  110.                         BootLoader_EraseFlash();
  111.                         printf("EraseFlash successfully \r\n");
  112.                         ymodem_t.OTA_FLAG = 1;
  113.                         ymodem_t.YMODE_FLAG = 1;
  114.         }
  115. }

  116. /***************************************************************************
  117. Ymodem数据帧:        
  118.                 帧头                  包号 包号反码         信息块                                                 校验
  119.         SOH/STX                 PN                 XPN                         DATA 128/1024                 CRC16(CRCH CRCL)
  120.                 1:对于SOH帧,若余下数据小于128字节,则以0x1A填充,该帧长度仍为133字节。
  121.                 2:对于STX帧需考虑几种情况

  122. 帧长度:
  123.                 1:以SOH(0x01)开始的数据包,信息块是128字节,该类型帧总长度为133字节
  124.                 2:以STX(0x02)开始的数据包,信息块是1024字节,该类型帧总长度为1029字节
  125.                         a:●余下数据等于1024字节,以1029长度帧发送;
  126.                         b:●余下数据小于1024字节,但大于128字节,以1029字节帧长度发送,无效数据以0x1A填充
  127.                         c:●余下数据等于128字节,以133字节帧长度发送
  128.                         d:●余下数据小于128字节,以133字节帧长度发送,无效数据以0x1A填充

  129. 包序号:
  130.         数据包序号只有1字节,因此计算范围是0~255;对于数据包大于255的,序号归零重复计算。

  131. 校验:
  132.         Ymodem采用的是CRC16校验算法,校验值为2字节,传输时CRC高八位在前,低八位在后;CRC计算数据为信息块数据,不包含帧头、包号、包号反码

  133. 起始帧:
  134.         Ymodem起始帧并不直接传输文件内容,而是先将文件名和文件大小置于数据帧中传输;起始帧是以SOH 133字节长度帧传输,格式如下
  135.         帧头                          包号 包号反码                 文名件称                                          文件大小                                                        填充区                                 校验
  136.         SOH/STX                PN                 XPN                                fileName+0x00                                fileSize+0x00                                                0x00                                CRC16(CRCH CRCL)

  137. Ymodem结束帧
  138.                 帧头                  包号         包号反码                         信息块                                                 校验
  139.                 SOH                                 PN                         XPN                                  0x00                                                        CRC16(CRCH CRCL)
  140.                
  141.                
  142. 文件传输过程

  143. 文件的传输过程,以具体的例子说明。把foo.c,大小为4196Byte(16进制为0x1064)的文件作为传输的对象,则它的传输过程如下:
  144. 发送端----------------------------------------------------------------接收端

  145. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C

  146. SOH 00 FF “foo.c” "1064’’ NUL[118] CRC CRC >>>>>>>>>>>>>

  147. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

  148. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C

  149. STX 01 FE data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>>

  150. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

  151. STX 02 FD data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>

  152. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

  153. STX 03 FC data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>

  154. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

  155. STX 04 FB data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>

  156. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

  157. SOH 05 FA data[100] 1A[28] CRC CRC>>>>>>>>>>>>>>>>>>

  158. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

  159. EOT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

  160. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< NAK

  161. EOT>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

  162. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

  163. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C

  164. SOH 00 FF NUL[128] CRC CRC >>>>>>>>>>>>>>>>>>>>>>>

  165. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK        
  166. *******************************************************************************************/

  167. void Ymodem_Receive(uint8_t *data,uint16_t datalen)
  168. {
  169.         char *fileSizebuff;
  170.         char fileSize[50];                        //文件大小
  171.         uint8_t i = 0,j=0;
  172.         
  173.         if(ymodem_t.OTA_FLAG == YMODEM_DISABLE)
  174.         {
  175.                 BootLoader_Com(data);
  176.         }
  177.         
  178.         //当是第0包数据时,和最1后才能进入,
  179.         if((data[0] == SOH && data[1] == 0x00 && data[2] == 0xff && ymodem_t.YMODE_Frist_Pack_FLAG == YMODEM_DISABLE && datalen == YMODE_SOH_PACKLEN) || ymodem_t.YMODE_Frist_FLAG == YMODEMD_ENABLE )        //Ymodem起始帧: 113
  180.         {               
  181.                         ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_SOH_DATALEN);
  182.                         if(ymodem_t.crc == ((data[YMODE_SOH_PACKLEN - 2]<<8) |data[YMODE_SOH_PACKLEN - 1]))        //CRC
  183.                         {
  184.                                        
  185.                                         if(ymodem_t.YMODE_Frist_FLAG == YMODEM_DISABLE)        //第1次
  186.                                         {
  187.                                                 ymodem_t.YMODE_FLAG = YMODEM_DISABLE;
  188.                                                 ymodem_t.YMODE_Frist_Pack_FLAG = YMODEMD_ENABLE ;        //第1包接收标志位置使能,说时第一包接好
  189.                                                 for(i=0;data[3+i] !='\0';i++)                //读取文件名
  190.                                                 {
  191.                                                         ymodem_t.fileName[i] = data[3+i];
  192.                                                 }
  193.                                                 i++;
  194.                                                 for(j=0;data[3+i+j] != '\0';j++)        //读取文件大小
  195.                                                 {
  196.                                                         fileSize[j] = data[3+i+j];
  197.                                                 }
  198.                                                 
  199.                                                         ymodem_t.fileSize = strtol(fileSize,&fileSizebuff,10);
  200.                                                         ymodem_t.remanider =         ymodem_t.fileSize % YMODE_SOH_DATALEN;        
  201.                                                         ymodem_t.packnum   =        ymodem_t.fileSize /        YMODE_SOH_DATALEN;
  202.                                                         if(ymodem_t.remanider > 0)
  203.                                                                 ymodem_t.packnum = ymodem_t.packnum+1;
  204.                                                         
  205.                                                 BootLoader_SendByte(ACK);        //正确发送ACK
  206.                                                 BootLoader_SendByte(CA);
  207.                                         }
  208.                                         else if(ymodem_t.YMODE_Frist_FLAG == YMODEMD_ENABLE)
  209.                                         {
  210.                                                 
  211.                                                 BootLoader_SendByte(ACK);        //正确发送ACK
  212.                                                 
  213.                                                 BootLoader_SendByte(CA);        //正确发送ACK

  214.                                                 Delay_ms(20);
  215.                                                 printf("\r\n");
  216.                                                 printf("fileName :%s \r\n",ymodem_t.fileName);
  217.                                                 printf("fileSize :%d Byte\r\n",ymodem_t.fileSize);
  218.                                                 printf("File uploaded successfully  \r\n");
  219.                                                 printf("\r\n");
  220.                                                 Ymodem_Init();
  221.                                                 BootLoader_To_App();
  222.                                                 
  223.                                         }
  224.                         }
  225.                         else{
  226.                                 BootLoader_SendByte(NAK);        //错误发送NAK
  227.                         }
  228.                         
  229.         }
  230.         else if((data[0] == STX && data[1] == 0x00 && data[2] == 0xff && ymodem_t.YMODE_Frist_Pack_FLAG == YMODEM_DISABLE && datalen == YMODE_STX_PACKLEN))        ////Ymodem起始帧: 1024
  231.         {
  232.                         ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_STX_DATALEN);
  233.                         if(ymodem_t.crc == ((data[YMODE_STX_PACKLEN - 2]<<8) |data[YMODE_STX_PACKLEN - 1]))        //CRC
  234.                         {
  235.                                         if(ymodem_t.YMODE_Frist_FLAG == YMODEM_DISABLE)        //第1次
  236.                                         {
  237.                                                 ymodem_t.YMODE_FLAG = YMODEM_DISABLE;
  238.                                                 ymodem_t.YMODE_Frist_Pack_FLAG = YMODEMD_ENABLE;        //第1包接收标志位置使能,说时第一包接好
  239.                                                 
  240.                                                 for(i=0;data[3+i] !='\0';i++)                //读取文件名
  241.                                                 {
  242.                                                         ymodem_t.fileName[i] = data[3+i];
  243.                                                 }
  244.                                                 i++;
  245.                                                 for(j=0;data[3+i+j] != '\0';j++)        //读取文件大小
  246.                                                 {
  247.                                                         fileSize[j] = data[3+i+j];
  248.                                                 }
  249.                                                         ymodem_t.fileSize = strtol(fileSize,&fileSizebuff,10);
  250.                                                 

  251.                                                 
  252.                                                         //数据1024时,数据是1024时,按1024接收,当小于1024时,以每包128个字传接收,直到所有数据收完
  253.                                                         ymodem_t.remanider =         ymodem_t.fileSize % YMODE_STX_DATALEN;                //余下字节个数
  254.                                                         
  255.                                                         ymodem_t.remaniderpacknum = ymodem_t.remanider / YMODE_SOH_DATALEN;        //余下字节以128接收的包数据
  256.                                                         
  257.                                                         ymodem_t.packnum   =        (ymodem_t.fileSize /        YMODE_STX_DATALEN)  ;                //1024总包数        
  258.                                                         if(ymodem_t.remanider  > 0)
  259.                                                         {
  260.                                                                 ymodem_t.remaniderpacknum = ymodem_t.remaniderpacknum +1;
  261.                                                                 ymodem_t.packnum = ymodem_t.packnum+1;
  262.                                                         }
  263.                                                         
  264.                                                         ymodem_t.YMODE_EOH_STX_DATALEN_FLAG = YMODEMD_ENABLE;                        
  265.                                        
  266.                                                 BootLoader_SendByte(ACK);        //正确发送ACK
  267.                                                 BootLoader_SendByte(CA);
  268.                                                         
  269.                                         }        
  270.                         }
  271.                         else{
  272.                                 BootLoader_SendByte(NAK);        //错误发送NAK
  273.                         }
  274.         }
  275.         else if(data[0] == SOH && datalen == YMODE_SOH_PACKLEN)        //Ymodem数据帧:当数据以大小是128字节时
  276.         {                        
  277.                         ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_SOH_DATALEN);
  278.                         if(ymodem_t.crc == ((data[YMODE_SOH_PACKLEN - 2]<<8) |data[YMODE_SOH_PACKLEN - 1]))        //CRC
  279.                         {
  280.                                                 ymodem_t.num ++;        //已接收的数据包数量+1
  281.                                        
  282.                                                 //将本次接收的数据,暂存到ymodem_t.UpdataBuffer缓冲                                                
  283.                                                         memcpy(&ymodem_t.UpdataBuffer[((ymodem_t.num - 1) % (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) * YMODE_SOH_DATALEN],&data[3], YMODE_SOH_DATALEN);   //将本次接收的数据,暂存到UpDataA.Updatabuff缓冲区
  284.                                                 if(ymodem_t.YMODE_EOH_STX_DATALEN_FLAG == YMODEM_DISABLE)        //当是128每包数据时
  285.                                                 {
  286.                                                         if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) == 0) &&( ymodem_t.packnum!=ymodem_t.num ))        //每满一个扇区写入Flash
  287.                                                         {                                                        
  288.                                                                 //写入到单片机A区相应的扇区
  289.                                                                 BootLoader_WriteFlash(STM32_A_SADDR + (((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) -1) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,STM32_PAGE_SIZE);    //写入到单片机A区相应的扇区
  290.                                                                
  291.                                                                 //备份FLASG写入
  292.                                                         }
  293.                                                         else if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) != 0) &&(ymodem_t.packnum==ymodem_t.num))//最后一包数,判断是否还有不满1扇区1024字节的数据,如果有进入if,把剩余的小尾巴写入
  294.                                                         {
  295.                                                                 //写入到单片机A区相应的扇区
  296.                                                                 BootLoader_WriteFlash(STM32_A_SADDR  + (((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN))) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,(ymodem_t.num % (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) * YMODE_SOH_DATALEN);    //写入到单片机A区相应的扇区
  297.                                                                
  298.                                                                 //备份FLASG写入        
  299.                                                         }
  300.                                                 }
  301.                                                 else {
  302.                                                         if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) == 0) &&( ymodem_t.remaniderpacknum!=ymodem_t.num ))        //每满一个扇区写入Flash
  303.                                                         {                                                        
  304.                                                                 //写入到单片机A区相应的扇区
  305.                                                                 BootLoader_WriteFlash(STM32_A_SADDR + (ymodem_t.STXnum * STM32_PAGE_SIZE)+(((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) -1) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,STM32_PAGE_SIZE);    //写入到单片机A区相应的扇区
  306.                                                                
  307.                                                                 //备份FLASG写入
  308.                                                         }        
  309.                                                         else if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) != 0) &&(ymodem_t.remaniderpacknum==ymodem_t.num))//最后一包数,判断是否还有不满1扇区1024字节的数据,如果有进入if,把剩余的小尾巴写入
  310.                                                         {
  311.                                                                 //写入到单片机A区相应的扇区
  312.                                                                 BootLoader_WriteFlash(STM32_A_SADDR + (ymodem_t.STXnum * STM32_PAGE_SIZE) + (((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN))) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,(ymodem_t.num % (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) * YMODE_SOH_DATALEN);    //写入到单片机A区相应的扇区                                                
  313.                                                                
  314.                                                                 //备份FLASG写入        
  315.                                                         }                                                        
  316.                                                 }

  317.                                                 BootLoader_SendByte(ACK);        //正确发送ACK
  318.                                                         
  319.                         }
  320.                         else{
  321.                                 BootLoader_SendByte(NAK);        //错误发送NAK
  322.                         }
  323.         }
  324.         else if(data[0] == STX && datalen == YMODE_STX_PACKLEN)        //Ymodem数据帧:当数据是1029字节时
  325.         {
  326.                         ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_STX_DATALEN);
  327.                         if(ymodem_t.crc == ((data[YMODE_STX_PACKLEN - 2]<<8) |data[YMODE_STX_PACKLEN - 1]))        //CRC
  328.                         {
  329.                                 ymodem_t.STXnum++;
  330.                                 memcpy(&ymodem_t.UpdataBuffer[((ymodem_t.STXnum- 1) % (STM32_PAGE_SIZE / YMODE_STX_DATALEN)) * YMODE_STX_DATALEN],&data[3], YMODE_STX_DATALEN);   //将本次接收的数据,暂存到UpDataA.Updatabuff缓冲区
  331.                                 if(((ymodem_t.STXnum % (STM32_PAGE_SIZE/YMODE_STX_DATALEN)) == 0) &&( ymodem_t.packnum!=ymodem_t.STXnum))        //每满一个扇区写入Flash
  332.                                 {                                                        
  333.                                         //写入到单片机A区相应的扇区
  334.                                         BootLoader_WriteFlash(STM32_A_SADDR + (((ymodem_t.STXnum/ (STM32_PAGE_SIZE / YMODE_STX_DATALEN)) -1) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,STM32_PAGE_SIZE);    //写入到单片机A区相应的扇区
  335.                                        
  336.                                         //备份FLASG写入
  337.                                        
  338.                                 }
  339.                                 
  340.                                 BootLoader_SendByte(ACK);        //正确发送ACK
  341.                         }
  342.                         else{
  343.                                 BootLoader_SendByte(NAK);        //错误发送NAK
  344.                         }
  345.                
  346.         }
  347.         else if(data[0] == EOT && datalen == YMODE_EOT_DATALEN)        //当接收到EOT
  348.         {        
  349.                 if(ymodem_t.count == 0)
  350.                 {
  351.                         ymodem_t.count ++;
  352.                         BootLoader_SendByte(NAK);        //正确发送NAK

  353.                 }
  354.                 else if(ymodem_t.count == 1)
  355.                 {
  356.                         ymodem_t.YMODE_Frist_FLAG = YMODEMD_ENABLE;
  357.                         ymodem_t.count = 0;
  358.                         BootLoader_SendByte(ACK);        //正确发送ACK                        
  359.                         BootLoader_SendByte(CA);        //正确发送C        

  360.                 }
  361.         }
  362.         else if(data[0] == CAN && data[1] == CAN && data[2] == CAN && data[3] == CAN && data[4] == CAN )        //取消传输命令,连续发送5个该命令
  363.         {
  364.                         ymodem_t.OTA_FLAG = YMODEM_DISABLE;
  365.                         Ymodem_Init();
  366.         }
  367. }


  1. #ifndef __YMODEM_H
  2. #define __YMODEM_H

  3. #include "stm32f4xx.h"

  4. #define  STM32_FLASH_SADDR   0x08000000                                                              //FLASH扇区起始地址
  5. #define  STM32_PAGE_SIZE     1024                                                                    //FLASH扇区大小
  6. #define  STM32_PAGE_NUM      1024                                                                     //FLASH扇区总个数
  7. #define  STM32_B_PAGE_NUM    16                                                                      //BootLoader 扇区个数

  8. #define  STM32_A_PAGE_NUM    (STM32_PAGE_NUM - STM32_B_PAGE_NUM)                                                                                                         //APP扇区个数
  9. #define  STM32_A_START_PAGE  (STM32_B_PAGE_NUM)                                                                                                                                                                                //APP扇区起始数
  10. #define  STM32_A_SADDR       (STM32_FLASH_SADDR + STM32_A_START_PAGE * STM32_PAGE_SIZE)                //APP扇区起始地址

  11. #define APPLICATION_ADDRESS (STM32_A_SADDR)                                                                                                                                                                                                //APP跳转地址


  12. #define YMODE_SOH_PACKLEN 133                        //SOH数据包长度
  13. #define YMODE_STX_PACKLEN 1029                //SOH数据包长度        
  14. #define YMODE_SOH_DATALEN 128                        //SOH有效数据长度
  15. #define YMODE_STX_DATALEN 1024                //SOH有效数据长度        
  16. #define YMODE_EOT_DATALEN   1

  17. typedef enum {YMODEM_DISABLE = 0, YMODEMD_ENABLE = !YMODEM_DISABLE} YmodemState;

  18. typedef enum{
  19.         SOH = 0X01,//133字节长度帧
  20.         STX = 0X02,//1024字节长度帧
  21.         EOT = 0X04,//文件传输结束命令
  22.         ACK = 0X06,//接收正确应答命令
  23.         NAK = 0X15,//重传当前数据包请求命令
  24.         CAN = 0X18,//取消传输命令,连续发送5个该命令
  25.         CA   = 0X43,//字符C ,发送握手        
  26. }YMODEM_COM;

  27. void Ymodem_Init(void);
  28. void BootLoader_Meun(void);
  29. void Ymodem_Receive(uint8_t *data,uint16_t datalen);
  30. #endif

usart.c
  1. #include "usart.h"
  2. #include "delay.h"
  3. uint8_t Usart1_RxBuffer[UARTx_RX_SIZE] = {0};      //串口1接收缓冲区
  4. uint8_t Usart1_TxBuffer[UARTx_TX_SIZE] = {0};      //串口1发送缓冲区
  5. Usartx_Control_Block  usart1;                                  //串口1控制结构体

  6. void (*usartTakeFunCb)(uint8_t *data,uint16_t datalen);

  7. void usart1TakeCb(void(*pFunc)(uint8_t *data,uint16_t datalen))
  8. {
  9.         usartTakeFunCb = pFunc;
  10. }

  11. void usart1_take(void)
  12. {
  13.         if(usart1.RxOutPtr != usart1.RxInPtr)
  14.         {
  15.                 usartTakeFunCb(usart1.RxOutPtr->start,(usart1.RxOutPtr->end - usart1.RxOutPtr->start+1));
  16.                
  17.                 usart1.RxOutPtr++;
  18.                 if(usart1.RxOutPtr == usart1.RxEndPtr)
  19.                 {
  20.                         usart1.RxOutPtr = &usart1.RxLocation[0];
  21.                 }
  22.         }

  23.         if((usart1.TxOutPtr != usart1.TxInPtr) &&( usart1.TxState == 0))
  24.         {
  25.                 usart1.TxState = 1;
  26.                
  27.                 DMA_Cmd(DMA2_Stream7,ENABLE);       
  28.                 while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE);        //确保DMA可以被设置
  29.                 DMA_SetCurrDataCounter(DMA2_Stream7, UARTx_TX_MAX);               
  30.                 usart1.TxOutPtr++;
  31.                 if(usart1.TxOutPtr == usart1.TxEndPtr)
  32.                 {
  33.                         usart1.TxOutPtr = &usart1.TxLocation[0];
  34.                 }
  35.        
  36.         }       
  37. }

  38. void USART1_Init(uint32_t bandRate)
  39. {
  40.         Usart1_PtrInit();
  41.         USART1_GPIO_Init();
  42.         Delay_ms(1);
  43.         USART1_Config_Init(bandRate);
  44.         Delay_ms(1);
  45.         USART1_DMA_Init();         
  46. }

  47. /*************************************************************************
  48. *        函 数 名: Uart1_RX_PtrInit
  49. *        功能说明: 串口1控制结构体各个指针初始化
  50. *        形    参:无
  51. *        返 回 值: 无
  52. **************************************************************************/
  53. void Usart1_PtrInit(void)
  54. {       
  55.         usart1.RxInPtr  = &usart1.RxLocation[0];
  56.         usart1.RxOutPtr = &usart1.RxLocation[0];
  57.         usart1.RxEndPtr = &usart1.RxLocation[9];
  58.         usart1.RxCounter = 0;
  59.         usart1.RxInPtr->start = Usart1_RxBuffer;

  60.         usart1.TxInPtr   = &usart1.TxLocation[0];
  61.         usart1.TxOutPtr  = &usart1.TxLocation[0];
  62.         usart1.TxEndPtr  = &usart1.TxLocation[9];
  63.         usart1.TxCounter = 0;
  64.         usart1.TxInPtr->start = Usart1_TxBuffer;
  65.        
  66.         memset(Usart1_RxBuffer,0,UARTx_RX_SIZE);
  67.         memset(Usart1_TxBuffer,0,UARTx_RX_SIZE);
  68. }

  69. /*************************************************************************
  70. *        函 数 名: Usart1_GPIO_Config
  71. *        功能说明: 串口1 GPIO初始化
  72. *        形    参:无
  73. *        返 回 值: 无
  74. **************************************************************************/

  75. void USART1_GPIO_Init(void)
  76. {
  77.   GPIO_InitTypeDef GPIO_InitStructure;
  78.                
  79.   RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE);
  80.        
  81.   /* 配置Tx引脚为复用功能  */
  82.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  83.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  84.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  85.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;       
  86.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        
  87.   GPIO_Init(GPIOB, &GPIO_InitStructure);
  88.        
  89.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7  ;
  90.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;       
  91.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  92.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;       
  93.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;           
  94.   GPIO_Init(GPIOB, &GPIO_InitStructure);       
  95.        
  96.        
  97.         /*串口上电发送0x00的解决*/
  98.   /* 连接 PXx 到 USARTx_Tx*/
  99.         GPIO_PinAFConfig(GPIOB,GPIO_PinSource6, GPIO_AF_USART1);

  100.         /*  连接 PXx 到 USARTx__Rx*/
  101.         GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_USART1);               
  102. }

  103. /*************************************************************************
  104. *        函 数 名: Usart1_Config
  105. *        功能说明: 串口1初始化
  106. *        形    参:bandRate:波特率
  107. *        返 回 值: 无
  108. **************************************************************************/
  109. void USART1_Config_Init(uint32_t bandRate)
  110. {

  111.   /* 使能 UART 时钟 */
  112.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  113.         usart1.usart.USART_BaudRate                       = bandRate;
  114.         usart1.usart.USART_WordLength                   = USART_WordLength_8b;                     //8bit数据位
  115.         usart1.usart.USART_StopBits                           = USART_StopBits_1;                        //1bit停止位
  116.         usart1.usart.USART_Parity                           =          USART_Parity_No;                         //无校验
  117.         usart1.usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  118.         usart1.usart.USART_Mode                               = USART_Mode_Rx | USART_Mode_Tx;      
  119.         USART_Init(USART1, &usart1.usart);       

  120. //        USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);        //开启空闲中断
  121.         USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);        //开启空闲中断
  122. //        USART_ITConfig(USART1,USART_IT_TC,ENABLE);        //开启发送完成中断       
  123.         USART_Cmd(USART1, ENABLE);                                                                                                                                //使能串口       
  124.        
  125.         USART_DMACmd(USART1,USART_DMAReq_Rx, ENABLE);                                                                        //使能RX DMA
  126.         USART_DMACmd(USART1,USART_DMAReq_Tx, ENABLE);                                                                        //使能RX DMA               
  127. }

  128. /*************************************************************************
  129. *        函 数 名: Uart1_DMA_Init
  130. *        功能说明: 串口1 DMA初始化
  131. *        形    参:无
  132. *        返 回 值: 无
  133. **************************************************************************/
  134. void USART1_DMA_Init(void)
  135. {
  136.        
  137.         NVIC_InitTypeDef NVIC_InitStructure;
  138.        
  139.         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
  140.   /* 复位初始化DMA数据流 */
  141.   DMA_DeInit(DMA2_Stream5);

  142.   /* 确保DMA数据流复位完成 */
  143.   while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE)  {
  144.   }

  145.   /*usart1 rx对应dma2,通道4,数据流2*/       
  146.   usart1.dmarx.DMA_Channel = DMA_Channel_4;  
  147.   /*设置DMA源:串口数据寄存器地址*/
  148.   usart1.dmarx.DMA_PeripheralBaseAddr =  (USART1_BASE + 0x04);         
  149.   /*内存地址(要传输的变量的指针)*/
  150.   usart1.dmarx.DMA_Memory0BaseAddr = (uint32_t)Usart1_RxBuffer;
  151.   /*方向:从内存到外设*/               
  152.   usart1.dmarx.DMA_DIR = DMA_DIR_PeripheralToMemory;       
  153.   /*传输大小DMA_BufferSize=RECEIVEBUFF_SIZE*/       
  154.   usart1.dmarx.DMA_BufferSize = UARTx_RX_MAX+1;
  155.   /*外设地址不增*/            
  156.   usart1.dmarx.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  157.   /*内存地址自增*/
  158.   usart1.dmarx.DMA_MemoryInc = DMA_MemoryInc_Enable;       
  159.   /*外设数据单位*/       
  160.   usart1.dmarx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  161.   /*内存数据单位 8bit*/
  162.   usart1.dmarx.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;       
  163.   /*DMA模式:不断循环*/
  164.   usart1.dmarx.DMA_Mode = DMA_Mode_Circular;         
  165.   /*优先级:中*/       
  166.   usart1.dmarx.DMA_Priority = DMA_Priority_Medium;      
  167.   /*禁用FIFO*/
  168.   usart1.dmarx.DMA_FIFOMode = DMA_FIFOMode_Disable;        
  169.   usart1.dmarx.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;   
  170.   /*存储器突发传输 16个节拍*/
  171.   usart1.dmarx.DMA_MemoryBurst = DMA_MemoryBurst_Single;   
  172.   /*外设突发传输 1个节拍*/
  173.   usart1.dmarx.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;   
  174.   /*配置DMA2的数据流2*/                  
  175.   DMA_Init(DMA2_Stream5, &usart1.dmarx);
  176.   
  177. //  /*使能DMA*/
  178.   DMA_Cmd(DMA2_Stream5, ENABLE);
  179.   
  180.   /* 等待DMA数据流有效*/
  181.   while(DMA_GetCmdStatus(DMA2_Stream5) != ENABLE)
  182.   {
  183.   }

  184.   /* 复位初始化DMA数据流 */
  185.   DMA_DeInit(DMA2_Stream7);

  186.   /* 确保DMA数据流复位完成 */
  187.   while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE)  {
  188.   }

  189.   /*usart1 tx对应dma2,通道4,数据流7*/       
  190.   usart1.dmatx.DMA_Channel = DMA_Channel_4;  
  191.   /*设置DMA源:串口数据寄存器地址*/
  192.   usart1.dmatx.DMA_PeripheralBaseAddr =  (USART1_BASE+0x04);         
  193.   /*内存地址(要传输的变量的指针)*/
  194.   usart1.dmatx.DMA_Memory0BaseAddr = (uint32_t)Usart1_TxBuffer;
  195.   /*方向:从内存到外设*/               
  196.   usart1.dmatx.DMA_DIR = DMA_DIR_MemoryToPeripheral;       
  197.   /*传输大小DMA_BufferSize=SENDBUFF_SIZE*/       
  198.   usart1.dmatx.DMA_BufferSize = UARTx_TX_MAX;
  199.   /*外设地址不增*/            
  200.   usart1.dmatx.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  201.   /*内存地址自增*/
  202.   usart1.dmatx.DMA_MemoryInc = DMA_MemoryInc_Enable;       
  203.   /*外设数据单位*/       
  204.   usart1.dmatx.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  205.   /*内存数据单位 8bit*/
  206.   usart1.dmatx.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;       
  207.   /*DMA模式:不断循环*/
  208.   usart1.dmatx.DMA_Mode = DMA_Mode_Circular;         
  209.   /*优先级:中*/       
  210.   usart1.dmatx.DMA_Priority = DMA_Priority_Medium;      
  211.   /*禁用FIFO*/
  212.   usart1.dmatx.DMA_FIFOMode = DMA_FIFOMode_Disable;        
  213.   usart1.dmatx.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;   
  214.   /*存储器突发传输 16个节拍*/
  215.   usart1.dmatx.DMA_MemoryBurst = DMA_MemoryBurst_Single;   
  216.   /*外设突发传输 1个节拍*/
  217.   usart1.dmatx.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;   
  218.   /*配置DMA2的数据流7*/                  
  219.   DMA_Init(DMA2_Stream7, &usart1.dmatx);
  220. //  
  221. //  /*使能DMA*/
  222. //  DMA_Cmd(DMA2_Stream7, ENABLE);
  223. //  
  224. //  /* 等待DMA数据流有效*/
  225. //  while(DMA_GetCmdStatus(DMA2_Stream7) != ENABLE)
  226. //  {
  227. //  }


  228.         DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);
  229.         DMA_ITConfig(DMA2_Stream7,DMA_IT_TC,ENABLE);
  230.         // NVIC  
  231.         NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;  
  232.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  
  233.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  234.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  235.         NVIC_Init(&NVIC_InitStructure);  

  236.         NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;  
  237.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  
  238.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  239.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  240.         NVIC_Init(&NVIC_InitStructure);   
  241.   
  242.         NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream5_IRQn;  
  243.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  
  244.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  245.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  246.         NVIC_Init(&NVIC_InitStructure);  
  247. }

  248. void Usart1_Txdata(uint8_t *tdata,uint16_t datalen)
  249. {
  250.         if(datalen == 0)
  251.         {
  252.                         DMA_SetCurrDataCounter(DMA2_Stream7, UARTx_TX_MAX);       
  253.                         return;
  254.         }
  255.         if((UARTx_TX_SIZE - usart1.TxCounter) >= datalen) //发送空间大于等于发数据
  256.         {
  257.                 usart1.TxInPtr ->start = &Usart1_TxBuffer[usart1.TxCounter];
  258.         }else
  259.         {
  260.                 usart1.TxCounter = 0;        //发送空间小于发送数据,清0
  261.                 usart1.TxInPtr->start = Usart1_TxBuffer;
  262.         }
  263.        
  264.        
  265.         while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE);        //确保DMA可以被设置
  266.         DMA_SetCurrDataCounter(DMA2_Stream7,datalen);                        //设置数据传输长度
  267.        
  268.         memcpy(usart1.TxInPtr ->start,tdata,datalen);        //数据拷贝
  269.        
  270.         usart1.TxCounter += datalen;        //统计每次发送量
  271.         usart1.TxInPtr ->end = &Usart1_TxBuffer[usart1.TxCounter-1];//标记end位,为下次作准备
  272.         DMA2_Stream7->M0AR  = (uint32_t)usart1.TxInPtr->start;

  273.         usart1.TxInPtr++;
  274.         if(usart1.TxInPtr == usart1.TxEndPtr){
  275.                 usart1.TxInPtr = &usart1.TxLocation[0];               
  276.         }
  277. }

  278. void Usartx_SendArray( USART_TypeDef * pUSARTx, uint8_t *data, uint16_t datalen)
  279. {
  280.         uint16_t i;
  281.         for(i=0;i<datalen;i++)
  282.         {
  283.             /* 发送一个字节数据到USART */
  284.             pUSARTx->DR = data[i];               
  285.                 while(!(pUSARTx->SR & USART_FLAG_TXE) );
  286.         }
  287.         while(!USART_GetFlagStatus(pUSARTx,USART_FLAG_TC));
  288. }

  289. void Usartx_SendStr( USART_TypeDef * pUSARTx, const char *SendStr)
  290. {
  291.         while(*SendStr != '\0')
  292.         {
  293.             /* 发送一个字节数据到USART */
  294.           // pUSARTx->DR = *SendStr;               
  295.                 USART_SendData(pUSARTx,*SendStr);
  296.                 //while(!USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE));
  297.                 while(!(pUSARTx->SR & USART_FLAG_TXE) );
  298.                 SendStr++;
  299.         }
  300.         while(!USART_GetFlagStatus(pUSARTx,USART_FLAG_TC));
  301. }

  302. //uint8_t tempbuff[256];
  303. //void u1_printf(char *fmt, ...)
  304. //{


  305. //        uint16_t i=0;       

  306. //        va_list ap;
  307. //        va_start(ap,fmt);
  308. //       
  309. //        vsprintf((char *)tempbuff,fmt,ap);
  310. //       
  311. //        va_end(ap);
  312. //        DMA_Cmd(DMA2_Stream7,DISABLE);
  313. //        for(i=0;i<strlen((char *)tempbuff);i++)
  314. //        {
  315. //                while(!USART_GetFlagStatus(USART1,USART_FLAG_TXE));
  316. //                USART1->DR = tempbuff[i];
  317. //        }
  318. //        //while(!USART_GetFlagStatus(USART1,USART_FLAG_TC));
  319. //}



  320. void USART1_IRQHandler(void)
  321. {
  322.         //发送中断
  323.         if(USART_GetITStatus(USART1,USART_IT_TC) != RESET)
  324.         {
  325.                 USART_ClearITPendingBit(USART1,USART_IT_TC);
  326.                 //usart1.TxState = 0;
  327.         }                               
  328.         //空闲中断
  329.         if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
  330.         {               
  331.                
  332.                 USART1->SR;                       //清中断
  333.                 USART1->DR;                       //清中断       
  334.                        
  335.                 usart1.RxCounter +=((UARTx_RX_MAX+1)- DMA_GetCurrDataCounter(DMA2_Stream5));
  336.                 usart1.RxInPtr->end = &Usart1_RxBuffer[usart1.RxCounter - 1];
  337.                
  338.                 usart1.RxInPtr++;
  339.                 if(usart1.RxInPtr == usart1.RxEndPtr)
  340.                 {
  341.                         usart1.RxInPtr = &usart1.RxLocation[0];
  342.                 }
  343.                 if((UARTx_RX_SIZE - usart1.RxCounter) >= UARTx_RX_MAX){
  344.                         usart1.RxInPtr->start = &Usart1_RxBuffer[usart1.RxCounter];         //标记接位置
  345.                                                                                
  346.                 }else{
  347.                         usart1.RxInPtr->start = Usart1_RxBuffer;
  348.                         usart1.RxCounter = 0;       
  349.                 }               
  350.                
  351.                 DMA_Cmd(DMA2_Stream5, DISABLE);     //关闭DMA
  352.                 DMA_SetCurrDataCounter(DMA2_Stream5, UARTx_RX_MAX+1);
  353.                 DMA2_Stream5->M0AR = (uint32_t)usart1.RxInPtr->start;
  354.                 DMA_Cmd(DMA2_Stream5, ENABLE);     //打开DMA                       
  355.         }       
  356. }

  357. void DMA2_Stream7_IRQHandler(void)
  358. {
  359.         if(DMA_GetITStatus(DMA2_Stream7,DMA_IT_TCIF7)!=RESET)//等待DMA2_Steam7传输完成
  360.         {               
  361.                 DMA_Cmd(DMA2_Stream7,DISABLE);                                //关闭使能
  362.                 DMA_ClearITPendingBit(DMA2_Stream7,DMA_FLAG_TCIF7); //清除DMA2_Steam7传输完成标志       
  363.                
  364.                 DMA_SetCurrDataCounter(DMA2_Stream7, UARTx_TX_MAX);               
  365.                 usart1.TxState = 0;
  366.         }
  367.         if(DMA_GetITStatus(DMA2_Stream7,DMA_IT_HTIF7)!=RESET)
  368.         {
  369.                 DMA_ClearITPendingBit(DMA2_Stream7,DMA_IT_HTIF7);
  370.         }

  371. }

  372. void DMA2_Stream5_IRQHandler(void)
  373. {
  374.         if(DMA_GetITStatus(DMA2_Stream5,DMA_IT_TCIF5)!=RESET)//等待DMA2_Steam2传输完成
  375.         {
  376.                 DMA_ClearITPendingBit(DMA2_Stream5,DMA_FLAG_TCIF5); //清除DMA2_Steam2传输完成标志       
  377.                 DMA_Cmd(DMA2_Stream5, ENABLE);   
  378.         }
  379.         if(DMA_GetITStatus(DMA2_Stream5,DMA_IT_HTIF5)!=RESET)
  380.         {
  381.                 DMA_ClearITPendingBit(DMA2_Stream5,DMA_FLAG_TCIF7);
  382.         }       

  383. }

  384. /* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */

  385. #if 1
  386. #if (__ARMCC_VERSION >= 6010050)                    /* 使用AC6编译器时 */
  387. __asm(".global __use_no_semihosting\n\t");          /* 声明不使用半主机模式 */
  388. __asm(".global __ARM_use_no_argv \n\t");            /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */

  389. #else
  390. /* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
  391. #pragma import(__use_no_semihosting)

  392. struct __FILE
  393. {
  394.     int handle;
  395.     /* Whatever you require here. If the only file you are using is */
  396.     /* standard output using printf() for debugging, no file handling */
  397.     /* is required. */
  398. };

  399. #endif

  400. /* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
  401. int _ttywrch(int ch)
  402. {
  403.     ch = ch;
  404.     return ch;
  405. }

  406. /* 定义_sys_exit()以避免使用半主机模式 */
  407. void _sys_exit(int x)
  408. {
  409.     x = x;
  410. }

  411. char *_sys_command_string(char *cmd, int len)
  412. {
  413.     return NULL;
  414. }

  415. /* FILE 在 stdio.h里面定义. */
  416. FILE __stdout;

  417. /* 重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
  418. int fputc(int ch, FILE *f)
  419. {
  420.     while ((USART1->SR & 0X40) == 0);               /* 等待上一个字符发送完成 */

  421.     USART1->DR = (uint8_t)ch;                       /* 将要发送的字符 ch 写入到DR寄存器 */
  422.        
  423.        
  424.     return ch;
  425. }

  426. #endif
  427. /***********************************************END*******************************************/

usart.h
  1. #ifndef __USART_H
  2. #define __USART_H
  3. #include "stm32f4xx.h"

  4. #include <stdint.h>
  5. #include "string.h"
  6. #include "signal.h"
  7. #include "stdarg.h"
  8. #include "stdio.h"
  9. #include "stdlib.h"
  10. #include <stdbool.h>

  11. #define UARTx_RX_SIZE   4096                 //接收缓冲区长度
  12. #define UARTx_TX_SIZE   4096                //发送缓冲区长度
  13. #define UARTx_RX_MAX    1029                        //单次接收最大量
  14. #define UARTx_TX_MAX    256                        //单次接收最大量
  15. #define SE_PTR_NUM      10                        //se指针对结构体数组长度


  16. typedef struct{
  17.     uint8_t *start;                                         //start用于标记起始位置                                                                       
  18.     uint8_t *end;                                        //end用于标记结束位置
  19. }LCB;                        //se 指针对结构体

  20. typedef struct{
  21.        
  22.        
  23.         uint16_t RxCounter;        //累计接收数据量
  24.         uint16_t TxCounter;
  25.         uint16_t TxState;
  26.         LCB RxLocation[SE_PTR_NUM];        //se指针对结构体数组
  27.         LCB *RxInPtr;                        //IN指针用于标记接收数据
  28.         LCB *RxOutPtr;                        //OUT指针用于提取接收的数据
  29.         LCB *RxEndPtr;                        ////IN和OUT指针的结尾标志
  30.        
  31.         LCB TxLocation[SE_PTR_NUM];        //se指针对结构体数组
  32.         LCB *TxInPtr;                        //IN指针用于标记发送数据
  33.         LCB *TxOutPtr;                        //OUT指针用于提取发送的数据
  34.         LCB *TxEndPtr;                        ////IN和OUT指针的结尾标志

  35.         USART_InitTypeDef usart;
  36.         DMA_InitTypeDef  dmatx;       
  37.         DMA_InitTypeDef  dmarx;
  38.        
  39. }Usartx_Control_Block;

  40. extern uint8_t Usart1_RxBuffer[UARTx_RX_SIZE];      //串口1接收缓冲区
  41. extern uint8_t Usart1_TxBuffer[UARTx_TX_SIZE];      //串口1发送缓冲区
  42. extern Usartx_Control_Block  usart1;                                                               //串口控制结构体


  43.   

  44. void USART1_Init(uint32_t bandRate);
  45. void USART1_GPIO_Init(void);
  46. void USART1_Config_Init(uint32_t bandRate);
  47. void USART1_DMA_Init(void);
  48. void Usart1_PtrInit(void);
  49. void Usart1_Txdata(uint8_t *tdata,uint16_t datalen);

  50. //void u1_printf(char *fmt, ...);
  51. void Usart1_Rx_Data(uint8_t *rdata);
  52. void usart1TakeCb(void(*pFunc)(uint8_t *data,uint16_t datalen));

  53. void usart1_take(void);


  54. void Clearsart3_RxBuffer(void);

  55. void Usartx_SendStr( USART_TypeDef * pUSARTx, const char *SendStr);
  56. void Usartx_SendArray( USART_TypeDef * pUSARTx, uint8_t *data, uint16_t datalen);
  57. #endif







zhengshuai888 发表于 2024-4-21 19:25 来自手机 | 显示全部楼层
Y我晕,还要付费才能看啊。
WoodData 发表于 2024-4-21 22:25 | 显示全部楼层
这种IAP都很简单了
 楼主| zero949079783 发表于 2024-4-21 23:14 | 显示全部楼层
WoodData 发表于 2024-4-21 22:25
这种IAP都很简单了

简单但是烦而已
lidi911 发表于 2024-4-22 08:35 来自手机 | 显示全部楼层
除了YModem还有XModem和ZModem
cmyldd 发表于 2024-5-11 10:01 | 显示全部楼层
协议是有许多种的, 原理差不多都一样,用熟哪种就那种
纠结的那些年 发表于 2024-8-31 16:04 | 显示全部楼层
配置STM32的USART串口用于与上位机通信。通常使用的引脚为TX和RX。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

91

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部