找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 11436|回复: 12
收起左侧

STM32与Proteus的串口仿真详细教程与源程序

  [复制链接]
ID:878474 发表于 2021-2-10 10:17 | 显示全部楼层 |阅读模式
包含LCD1602显示,串口发送接收,完美实现。
文档内容齐全,包含使用说明,相关驱动等。
解决了STM32的Proteus串口收发问题。    注意:每输入一个字符后,要按一次“手动发送”按钮,才能收到正确字符。

仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)

串口收发

串口收发


Proteus的串口仿真
打开串口调试助手,如图11-30所示。进入串口调试助手后,需要设置相关参数,串口号为图11-29所查到的端口号,其他参数根据实际程序来确定。打开串口后,按开发板上的reset按键,显示区就能接收到从开发板发送过来的“Welcome to HBEU”,每按复位键一次,就会接收一次,如图11-31所示;在发送区输入字符,如图11-32所示,点击“手动发送”,开发板上就能收到对应的字符,根据要求,不是以“x”结束的字符串,当超过20个字符后也接收到字符串。
图11-29 查看串口号
   在Proteus中仿真串口时,先安装“虚拟串口”驱动,如图11-33所示,安装完之后也可以查看虚拟串口的端口号,查看方法与图11-29一致。在串口助手中设置好串口参数后,按Proteus中运行按钮,也可以在串口助手收到信息,如图11-34所示,注意串口波特率。
图11-30 串口助手
图11-31 STM32发送数据
图11-32 STM32串口接收数据
图11-33 虚拟串口驱动文件
图11-34  Proteus仿真串口接收数据
由于Proteus没有对stm32的时钟树做仿真模型,只固定了一套时钟值,可以用GETSYS/HCLK/PCLK函数看。Proteus不是实时仿真,所以串口速率不是硬件速率对应的值,可能更高,可能更低,好在Proteus的虚拟终端是可以输入非标准波特率的,推荐波特率设为9600bit/s。另外,在Proteus仿真的程序中加了一条语句:
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
若没有该系统配置语句,则看不到仿真效果。仿真时钟跟实际时钟存在一定的延时误差,在上位机发送数据时,一次发送一个字符串时,接收会出现乱码,因此需要一个一个字符发送,如图11-35所示,在发送区依次输入“e1x”之后(注意:每输入一个字符后,要按一次“手动发送”按钮),虚拟终端(Virtual Terminal)会显示所发送的所有字符,当STM32的串口接收到字符“x”后,表示结束,在LCD屏上显示“e1”。
为了接收方便,将最多发送20个字符改为最多发送5个字符,当我们依次输入“123456”后(注意:每输入一个字符后,要按一次“手动发送”按钮),LCD显示收到的字符串“12345”,如图11-36所示。
图11-35  STM32串口遇到“x”结束接收   图11-36  STM32串口收到6个字符自动结束


单片机main文件源代码:
  1. #include "stm32f10x.h"
  2. #include "stdio.h"
  3. //#include "led.h"
  4. #include "delay.h"
  5. #include "lcd1602.h"


  6. uint8_t USART_RXBUF[5];
  7. extern uint8_t RXOVER;
  8. /* Private function prototypes -----------------------------------------------*/
  9. void NVIC_Configuration(void);
  10. //void Delay_Ms(uint32_t nTime);
  11. void USART_Config(void);
  12. //void USART_SendString(int8_t *str);
  13. void USART_SendString(unsigned char *buf);

  14. int main(void)
  15. {
  16.          uint8_t i;

  17.         RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);

  18.         //SysTick_Init();
  19.         SysTick_Config(SystemCoreClock/100000);
  20.    GPIO_Configuration();
  21.    LCD1602_Init();
  22.                
  23.         LCD1602_Show_Str(0,0,"Receive:");        
  24.         USART_Config();
  25.                 //USART_SendString(Tx_Buf);//发送字符串
  26.                 USART_SendString("Welcome to HBEU\r\n");//发送字符串
  27.         while(1)
  28.         {
  29.                 if(RXOVER == 1){

  30.                         LCD1602_Show_Str(0,2,USART_RXBUF);               
  31.                                 
  32.                         for(i=0;i<5;i++){
  33.                                 USART_RXBUF[i] =' ';  //清空接收区
  34.                         }
  35.                         RXOVER = 0;
  36.                         USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);/////////////////////////////////////////////////////////////
  37.                 }
  38.                
  39.                 /*if(USART_GetFlagStatus(USART1,USART_IT_RXNE)==SET)
  40.                 {
  41.                         USART_SendData(USART1,USART_ReceiveData(USART1));
  42.                         delay_ms(1000);
  43.                 }*/
  44.                                 
  45.         }
  46. }

  47. /*void USART_Config(void)
  48. {
  49.     GPIO_InitTypeDef  GPIO_InitStructure;
  50.     USART_InitTypeDef USART_InitStructure;

  51.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);
  52.         //RCC_APB1PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  53.         
  54.         //NVIC_Configuration();
  55.     //配置USART2 TX引脚工作模式
  56.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  57.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  58.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  59.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  60.     //配置USART2 RX引脚工作模式
  61.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  62.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  63.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  64.     //串口2工作模式配置
  65.     USART_InitStructure.USART_BaudRate = 9600;
  66.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  67.     USART_InitStructure.USART_StopBits = USART_StopBits_1;
  68.     USART_InitStructure.USART_Parity = USART_Parity_No ;
  69.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  70.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  71.     USART_Init(USART1, &USART_InitStructure);
  72.         
  73.         //USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
  74.     USART_Cmd(USART1, ENABLE);
  75. }*/

  76. void USART_Config(void)
  77. {
  78.         GPIO_InitTypeDef GPIO_InitStructure;
  79.         USART_InitTypeDef USART_InitStructure;

  80.         // 打开串口GPIO的时钟
  81.         //DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
  82.         
  83.         // 打开串口外设的时钟
  84.         //DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
  85.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  86.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
  87.         NVIC_Configuration();
  88.         // 将USART Tx的GPIO配置为推挽复用模式
  89.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  90.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  91.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  92.         GPIO_Init(GPIOA, &GPIO_InitStructure);

  93.   // 将USART Rx的GPIO配置为浮空输入模式
  94.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  95.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  96.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  97.         
  98.         // 配置串口的工作参数
  99.         // 配置波特率
  100.         USART_InitStructure.USART_BaudRate = 9600;
  101.         // 配置 针数据字长
  102.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  103.         // 配置停止位
  104.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  105.         // 配置校验位
  106.         USART_InitStructure.USART_Parity = USART_Parity_No ;
  107.         // 配置硬件流控制
  108.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  109.         // 配置工作模式,收发一起
  110.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  111.         // 完成串口的初始化配置
  112.         USART_Init(USART1, &USART_InitStructure);

  113.         // 使能串口
  114.         USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
  115.         USART_Cmd(USART1, ENABLE);            
  116. }

  117. /**
  118.   * @说明     USART2字符串发送函数
  119.   * @参数     str: 指向字符串的指针
  120.   * @返回值   None
  121.   */
  122. /*void USART_SendString(int8_t *str)
  123. {
  124.     uint8_t index = 0;

  125.     do
  126.     {
  127.         USART_SendData(USART1,str[index]);
  128.         while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
  129.         index++;        
  130.     }
  131.     while(str[index] != 0);  //检查字符串结束标志

  132. }*/

  133. void USART_SendString(unsigned char *buf)
  134. {
  135.         while (*buf != '\0')
  136.         {
  137.                 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
  138.                 USART_SendData(USART1, *buf++);

  139.         }
  140. }

  141. /**
  142.   * @说明     配置中断向量控制器
  143.   * @参数     None
  144.   * @返回值   None
  145.   */
  146. void NVIC_Configuration(void)
  147. {
  148.         NVIC_InitTypeDef NVIC_InitStructure;

  149.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  150.         /* Enable the RTC Interrupt */
  151.         NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  152.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  153.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  154.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  155.         NVIC_Init(&NVIC_InitStructure);
  156. }
复制代码
Proteus仿真工程与代码51hei下载:
资料.7z (7.93 MB, 下载次数: 426)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:605142 发表于 2021-2-11 08:16 | 显示全部楼层
keil 51hei图片20210211081423.png

Proteus 51hei图片20210211081454.png

我测试stm32 PWM仿真,Proteus仿真 跟keil软件仿真 出来的结果不一样
我也不知道信谁了,改天搭个硬件试一下
回复

使用道具 举报

ID:605142 发表于 2021-2-11 10:06 | 显示全部楼层

找到原因了,keil的是正确的
proteus 的PWM 模式1跟模式2是反的,
回复

使用道具 举报

ID:219983 发表于 2021-2-11 16:25 | 显示全部楼层
proteus确实是好东西,刚开始学习stm32,还在摸索中。
回复

使用道具 举报

ID:89414 发表于 2021-3-4 14:27 | 显示全部楼层
看着挺有用的
回复

使用道具 举报

ID:304785 发表于 2022-4-17 12:48 | 显示全部楼层
胡来一刀 发表于 2021-2-11 16:25
proteus确实是好东西,刚开始学习stm32,还在摸索中。

刚开始学习建议你直接上开发板,别用proteus。就算实际程序写了好多年,也玩不明白proteus的32仿真。
回复

使用道具 举报

ID:1023206 发表于 2022-5-13 19:14 | 显示全部楼层
太棒了,我要被实验愁死了
回复

使用道具 举报

ID:72243 发表于 2022-5-22 17:48 | 显示全部楼层
proteus的stm32单片机仿真非常的无语,很多情况与实际根本就是两回事。
千万不要想着51能仿真,32也没问题,那就大错特错了,正如楼上老兄所说,玩了N年32的也不一定能搞明白32的proteus仿真。
就拿串口仿真来说,同样是用虚拟串口proteus仿真,51就可以字符串收发。到了stm32,就和楼主说的一样,字符串只能从单片机发到上位机,单片机侧不能成串接收字符串,只能一个一个接收,尝试无数遍也没找原因也没有找到原因。
还有诸如系统滴答定时器,以及通用定时器设置,参数和实际设置差距不是一般的大,到现在我都不知道原因,真的是天、天、天、天壤之别。

评分

参与人数 1黑币 +40 收起 理由
admin + 40 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:1048085 发表于 2022-12-9 19:57 | 显示全部楼层
为什么我直接下载下来后运行就是不行呢 不管是单个字符发送还是发送字符串 LCD上都是显示乱码 串口助手的波特率设置9600
回复

使用道具 举报

ID:9932 发表于 2023-8-31 22:58 | 显示全部楼层
proteus确实是好东西,刚开始学习stm32
回复

使用道具 举报

ID:108931 发表于 2023-11-5 14:10 | 显示全部楼层
这个仿真真好。
回复

使用道具 举报

ID:294858 发表于 2023-11-30 11:08 | 显示全部楼层
我不能实现数据发送,能给了详细的步骤吗?
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表