你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】stm32 普通IO口模拟串口通信

[复制链接]
STMCU小助手 发布时间:2022-1-26 23:55
普通IO口模拟串口通信
  • 串口通信协议  
  • 1756507-20190801171211417-2072826917.png
  • 串口传输 默认 波特率9600 1起始位 1停止位 其他0 数据位是8位(注意图上的给错了)。
  • 传输时,从起始位开始,从一个数据的低位(LSB)开始发送,如图从左向右的顺序,对电平拉高或拉低,最后停止位时拉高。
  • 波特率大小,改变延时时间即可。例如9600 波特率    根据公式 : 1/9600=0.000104s(大致) 也就是说每发送1bit延时104us (下面我用9600波特率来说,代码用的是19200)
  • 串口发送       将电平拉低 延时104us(视为 起始位 0   传输数据正式开始)  其中数据我发送的是16进制数据(8bit  一字节  例如10001000)  将想要发的数据按照二进制的‘0’‘1’高低电平的方式,每发送1bit 延时104us   直到发送完到终止位 将电平拉高视为一包数据传输结束。(根据需求更改即可)
  • 串口接收    (稍微麻烦一些) 两种方法:第一种可以用定时中断,每隔104us开启一次定时中断,中断函数内进行高低电平判断,将这些bit存储最后转换成需要的数据。第二种,用外部中断处理函数,外部中断设置同时开启上升沿下降沿,思路:根据上升下降的电平跳变分析。比如说,触发外部中断后检测电平高低,记录一下当前时间,然后再进入外部中断后 计算出总共几个bit   (两个沿跳变之间的时间 =现在记录的时间 — 之前记录的时间        bit=这个时间/104us)  ,知道这个就可以转换数据了。
  • 定时中断逻辑相对外部中断而言简单好写,但是数据多的时候准确率下降很多,容易丢数据(因为定时中断毕竟用计时开启中断,不可能时间准确每104us开启一次,数据一多时间误差大,自然丢包。可以尝试每发一串数据,重新计时校准一次)。外部中断较为准确,检测的高低电平跳变较为明显唯一,一个跳变就是一个数据,只是分析情况比较多。
  1. //IO模拟串口初始化 1 void IRrec_Init(){
  2. 2
  3. 3
  4. 4     EXTI_InitTypeDef EXTI_InitStructure;
  5. 5     NVIC_InitTypeDef NVIC_InitStructure;
  6. 6     GPIO_InitTypeDef GPIO_InitStructure;
  7. 7
  8. 8     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能GPIOC时钟
  9. 9
  10. 10
  11. 11     //IR TX C9 使能
  12. 12     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  13. 13     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
  14. 14     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  15. 15     GPIO_Init(GPIOC, &GPIO_InitStructure);
  16. 16     GPIO_SetBits(GPIOC, GPIO_Pin_9);//  引脚拉高
  17. 17            
  18. 18
  19. 19     //IR RX C8
  20. 20     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
  21. 21     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  22. 22     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  23. 23     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  24. 24     GPIO_Init(GPIOC, &GPIO_InitStructure);
  25. 25     GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource8);
  26. 26
  27. 27     EXTI_InitStructure.EXTI_Line=EXTI_Line8;
  28. 28     EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
  29. 29     EXTI_InitStructure.EXTI_Trigger=      
  30. 30     EXTI_Trigger_Rising_Falling;
  31. 31     EXTI_InitStructure.EXTI_LineCmd=ENABLE;
  32. 32     EXTI_Init(&EXTI_InitStructure);
  33. 33     
  34. 34     NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn;
  35. 35     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
  36. 36     NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
  37. 37     NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  38. 38     NVIC_Init(&NVIC_InitStructure);
  39. 39         
  40. 40 }
复制代码
  1. void IR_SendByte(u8 val)//发送bit位
  2. {
  3.     u16 i;

  4.     IRSEND=0;//拉低 开始传输
  5.     SysTick_Delay_Us(53);//波特率根据延时在设置  19200波特率

  6.     for(i=0;i<8;i++)
  7.     {
  8.         if(val&0x1)
  9.         {
  10.             IRSEND=1;
  11.         }
  12.         else
  13.         {
  14.             IRSEND=0;
  15.         }

  16.         val>>=1;
  17.         SysTick_Delay_Us(53);
  18.     }

  19.     IRSEND=1;
  20.     SysTick_Delay_Us(53);
  21. }


  22. void IR_SendStr(u8*st,u16 len){//在这填入16位数据即可
  23.     int i=0;
  24.     while ((len--)!=0)
  25.     {
  26.         IR_SendByte(st[i]);
  27.         i++;
  28.     }

  29. }
复制代码
  1. u8 IRREC_RX_BUF[64]={0};    //接收缓冲,最大64个字节.
  2.     //接收到的数据长度
  3.     u8 IRREC_RX_CNT=0;

  4. char rebit=stopbit;//记录接收一个字节的二进制位所处何种位置
  5. u8 Recev[8]={0};//记录接收的一个字节的二进制流

  6. static volatile unsigned long long m_rx_previous_time = 0;//上一次进入中断时间
  7. static volatile unsigned char m_rx_begin_f = 0;//开始一个字节的接收标志 0-无数据开始接收 1-有数据开始接收
  8. void EXTI9_5_IRQHandler(void){

  9.     if(EXTI_GetITStatus(EXTI_Line8)!=RESET)
  10.     {
  11.         unsigned char skip_index = 0;
  12.         unsigned char i = 0;
  13.         unsigned char temp_bin = 0;//用于记录二进制值
  14.         unsigned long long current_time = sys_micros();//记下此刻时间
  15.         unsigned short interval_time = current_time - m_rx_previous_time;//计算一个状态持续的时长
  16.         m_rx_previous_time = current_time;//为下次计算时长做准备

  17.         //当前未开始一个字节的接收且此时为下降沿
  18.         if(rebit == 10)//10 当数据不合法时或者结束传输时 rebit值设为10
  19.         {
  20.             if(!PCin(8))//下降沿
  21.             {
  22.                 rebit = 0;//记下开始接收
  23.                 m_rx_begin_f = 1;
  24.                 debug_led(1,LED_TOGGLE);
  25.             }
  26.         }
  27.         //已经开始接收
  28.         else
  29.         {
  30.             //上一状态为起始位
  31.             if(!rebit)//起始位0
  32.             {
  33.                 //计算二进制数据的个数
  34.                 skip_index = (interval_time/50)-1;

  35.                 //个数合法
  36.                 if(skip_index <= 9)
  37.                 {
  38.                     //根据状态保持时间更新接收值
  39.                     for(i = 0;i < skip_index;i++)
  40.                     {
  41.                         Recev[i] = 0;

  42.                     }

  43.                     //更新接收二进制位的下标
  44.                     rebit = skip_index;

  45.                 }
  46.                 //不合法-重新接收
  47.                 else
  48.                 {
  49.                     rebit = 10;
  50.                     m_rx_begin_f = 0;


  51.                 }
  52.             }
  53.             //上一状态为数据位
  54.             else
  55.             {
  56.                 //计算二进制数据的个数
  57.                 skip_index = interval_time/50;

  58.                 //数据不合法-重新接收
  59.                 if((skip_index+rebit) > 9)//所处位置+数据个数 判断数据是否超10 合法判断
  60.                 {
  61.                     //printf("skip_index %d   rebit=%d \r\n",skip_index,rebit);
  62.                     rebit = 10;
  63.                     m_rx_begin_f = 0;
  64.                     debug_led(3,LED_TOGGLE);
  65.                 }
  66.                 //数据合法
  67.                 else
  68.                 {
  69.                     //当前为高电平
  70.                     if(PCin(8))
  71.                     {
  72.                      temp_bin = 1;//0
  73.                     }
  74.                     else
  75.                     {
  76.                      temp_bin = 0;//1 change
  77.                     }
  78.                     debug_led(2,LED_TOGGLE);
  79.                     for(i = 0;i < skip_index ;i++)//根据几个数据 给予相应的位
  80.                     {
  81.                         Recev[rebit+i+1] = temp_bin;//change +1
  82.                         rebit++;

  83.                     }
  84.                 }

  85.                 //数据已接收至结束位
  86.                 if(rebit >= 8 )//=8>?
  87.                 {
  88.                     if(IRREC_RX_CNT < 64)
  89.                     {
  90.                         IRREC_RX_BUF[IRREC_RX_CNT++]     = (Recev[7] << 7) |(Recev[6] << 6)| (Recev[5] << 5)| (Recev[4] << 4)| (Recev[3] << 3) |(Recev[2] << 2) |(Recev[1] << 1) |Recev[0];

  91.                     }
  92.                     rebit = 10;
  93.                     m_rx_begin_f = 0;


  94.                 }

  95.             }
  96.         }


  97.         #endif
  98.         EXTI_ClearITPendingBit(EXTI_Line8);//清除中断挂起标志位

  99.     }

  100. }
复制代码

收藏 评论0 发布时间:2022-1-26 23:55

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版