stm32普通IO口模拟串口通信(自己改的)

2019-07-21 03:00发布

要做个项目需要7个串口,MCU上串口不够需要自己模拟,就到本论坛上找,不过没找到,最终找了下资料用原子哥的串口实验例程改的,成功了拿来分享一下,要是有什么问题也希望大家指点一下, 平时老是从这里获取,也希望能为论坛做点贡献。
为了方便跟电脑串口连接,io口仍选用PA9与PA10,不过这里只将它们当作变通的IO口使用。PA9对应TXD,PA10对应RXD的功能。串口配置是波特率9600,8位数据位,1位停止位,无校验位。
不过我也有个疑问,因为这个是按照原子哥的串口例程改的,所以结束标志就是收到0x0d,0x0a,这样就必须发字符串的时候发送新行,发16进制数最后要有0x0d,0x0a。我看到我往串口调试助手发送数据,根本就没发固定的结束标志啊,它都能立即接收并显示出来,它是依次接收一个字节就显示一个字节吗?我试了一下,只能正常接收第一个字节后面的都丢了。




发送数据

void SendOneByte(u8 Byte) { u8 i=8,tmp; TXD_low(); //发送起始位 delay_us(104); //发送8位数据 for(i=0;i<8;i++) { tmp = (Byte >> i) & 0x01;  //低位在前
if(tmp == 0) { TXD_low(); delay_us(104); //0 } else { TXD_high(); delay_us(104); //1 } } // while(i--) // {   //  MNUSART_TXD = (Byte&0x01);     //先传低位 //  delay_us(104);   //  Byte = Byte>>1; //  //无校验位 //  MNUSART_TXD=1;//发送结束位 //  delay_us(104); // } TXD_high(); delay_us(104);
}
void SendBytes(u8 *str,u8 len) //发送数组最好用这个,也可发送字符串 {   u16 i;   for(i=0;i<len;i++)   {   SendOneByte(str);      }
}
void SendStr(u8 *str) //发送字符串,发送数组如果带0x00就中断发送了 {  while(*str)  SendOneByte(*str++);
}
接收用的外部中断

void EXTIX_Init(void) {    GPIO_InitTypeDef GPIO_InitStructure;    EXTI_InitTypeDef EXTI_InitStructure;    NVIC_InitTypeDef NVIC_InitStructure;    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 端口配置    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz    GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5    GPIO_SetBits(GPIOA,GPIO_Pin_9);      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  //浮空输入    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;          GPIO_Init(GPIOA, &GPIO_InitStructure);      GPIO_SetBits(GPIOA,GPIO_Pin_10);           //GPIOA.10 中断线以及中断初始化配置   下降沿触发   GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource10);
  EXTI_InitStructure.EXTI_Line=EXTI_Line10;   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;   EXTI_InitStructure.EXTI_LineCmd = ENABLE;   EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器

NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);  
}

void EXTI15_10_IRQHandler(void) {    u8 i=9;    if(EXTI_GetITStatus(EXTI_Line10) != RESET)    {      /* Disable the Selected IRQ Channels -------------------------------------*/      NVIC->ICER[EXTI15_10_IRQn >> 0x05] =       (uint32_t)0x01 << (EXTI15_10_IRQn & (uint8_t)0x1F);  EXTI_ClearITPendingBit(EXTI_Line10);  delay_us(30);  while(i--)  {   tmp >>=1; if(GPIOA->IDR&0x0400) tmp |=0x80; delay_us(104);  }  if((USART_RX_STA&0x8000)==0)  {   if(USART_RX_STA&0x4000) {  if(tmp!=0x0a) USART_RX_STA=0;  else USART_RX_STA |=0x8000; } else {   if(tmp==0x0d) USART_RX_STA|=0x4000;   else    {     USART_RX_BUF[USART_RX_STA&0X3FFF]=tmp ;    USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收     } }    }
 EXTI_ClearITPendingBit(EXTI_Line10);  NVIC->ISER[EXTI15_10_IRQn >> 0x05] =     (uint32_t)0x01 << (EXTI15_10_IRQn & (uint8_t)0x1F);
   }
}
主函数

int main(void)  {   u8 len;   u8 hello[]={0x5a,0xa5,0x00,0x00,0x01};   delay_init();   EXTIX_Init();   //测试 发送一个字节   SendOneByte(0x00);   SendOneByte(0x01);   SendOneByte(0x02);  //测试发送数组  SendBytes(hello,5);  //测试发送字符串 // SendBytes("hello word",11); // SendStr("德玛西亚");     while(1) {  if(USART_RX_STA&0x8000)  {       printf(" 您发送的消息为: ");   len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度 SendBytes(USART_RX_BUF,len); //也可以用下面的发送 // SendStr(USART_RX_BUF); // for(len=0;len<200;len++) // USART_RX_BUF[len]=0;   printf(" ");//插入换行 USART_RX_STA=0;  } }  }






友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
49条回答
602647310
1楼-- · 2019-07-22 02:47
楼主不错,顶起!
贵在坚持
2楼-- · 2019-07-22 07:42
 精彩回答 2  元偷偷看……
__小黑先生
3楼-- · 2019-07-22 09:42
回复【9楼】贵在坚持:
---------------------------------
楼主你这函数哪学的呢
为什么我查函数库都没看到呢
还是寄存器版的才有?
lilanqing81
4楼-- · 2019-07-22 10:23
回复【5楼】冰是睡着的水:

回复【楼主位】贵在坚持:
---------------------------------
你的模拟串口,接受部分代码写的不好,没有采样,,直接延迟。。。建议采样频率为波特率的3-5倍。。

---------------------------------
串口没有采样之说,不是频率信号。假设如果把串口波特率放慢到1秒一位,一个字节的数据按照1位起始,8位数据,1位停止,共需要10秒。
每个位(包括起始、停止)的数值是高或者低,都需要在这个位对应的秒时读取。

例如第3位为高电平,从第4秒到第5秒这一秒的时间中,任何时刻读取数值都可以。
但是只能读取一次,及时读取多次,也不能把后续读取的数值作为第4位,只有当第5秒和第6秒到来时,才能读取第4位。

楼主写的程序,我持赞成态度。
使用起始位的从低到高电平跳转上升沿,触发外部中断。
然后关闭外部中断,防止8位数据中出现的电平跳转再次触发中断。打乱下面的while部分。
再然后清除中断标志,使delay_us可以起作用,因为这个delay用的是系统滴答中断。
然后延迟30uS,此时取电平正好是第一位数据,取到第8次,数据取完,取第9次,取出停止位。

再然后就没什么好说的了。

我感觉最后两段话,开中断可以有,清中断标志就不必了。
贵在坚持
5楼-- · 2019-07-22 10:36
回复【10楼】__小黑先生:
---------------------------------
库函数里有的 void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct) 这个函数里面的
wzytwh
6楼-- · 2019-07-22 14:45
菜鸟的程序,在中断里接收,其他程序咱们办。
应该用外部中断和定时器配合做

一周热门 更多>