以前常听说码农需要有严密的逻辑思维,以前不明白。没有思维框架,真的很难写代码,不能瞎蒙,等我的只是效率低下

思路

首先我们要模拟串口通信,就要了解通信的必须条件,包括数据位及其他标志位,以及他的时序,有点像模拟IIC。

如图是数据的格式,数据位为八位,不是七位,当然也是有数据位为七位的,在实际的传输过程中,我选择起始位+数据为+停止位即可,奇偶校验位和空闲位不要,光是知道要传的数据,对方却不知道什么时候来接收此数据,所以我们现在需要一个协议(uart串口协议)来将数据放到这个协议上,这样就可以使得通信的上位机或者下位机能够识别传输的数据了,那还需要什么呢??
我们都知道我们在使用串口软件的时候都有设置,(只是举个例子,串口软件太多了)如图:

波特率、数据位、校验位、停止位都是可以更改的。
波特率概念:波特率表示每秒钟传送的码元符号的个数,它是对符号传输速率的一种度量,它用单位时间内载波调制状态改变的次数来表示,1波特即指每秒传输1个符号
一般的,我们采用模拟的形式来通信一般都在9600及以下,再高的话,精度无法保证。

在此,这里采用模拟波特率为9600的来做通信(正常来说波特率越低,难度越小)

9600的意思就是每一秒钟发送9600个bit(其中包括非数据位),注意这里不是字节(就不能当作9600/8=1200byte),很多没做过这个实验的小伙伴是不清楚这个概念的。理想情况下,按照这个传输波特率,发送每一位的时间间隔为104us,
要进行通信,就有发送与接收,发送相对接收来说要简单一点。

串口发送

发送中最重要的就是时间的控制,因为是微妙级的,需要很精确,我采用的是定时器计时。

定时器初始化:这里我们直接使用API即可(其中的hi_u32就是一个32位的数据定义),如果需要适配自己的IC,按照创建定时器创建即可

void io_hrtimer_init(hi_u32 *g_hrtimer)
{hi_u32 ret;/* create timer handle */ret = hi_hrtimer_create(g_hrtimer);//创建定时器if (ret != HI_ERR_SUCCESS){printf("=====ERROR===== hrtimer handle create ret is: %d !!\r\n", ret);return;}printf("----- hrtimer handle create success -----\n");
}

GPIO初始化:每一个API都有注释说明

void io_uart_tx_init(void)
{hi_u32 ret;ret = hi_gpio_init(); //GPIO初始化if (ret != HI_ERR_SUCCESS){printf("===== ERROR ===== gpio -> hi_gpio_init ret:%d\r\n", ret);return;}printf("----- gpio init success-----\r\n");ret = hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_GPIO);//开启GPIO复用if (ret != HI_ERR_SUCCESS){printf("===== ERROR ===== gpio -> hi_io_set_func ret:%d\r\n", ret);return;}printf("----- io set func success-----\r\n");ret = hi_gpio_set_dir(HI_GPIO_IDX_14, HI_GPIO_DIR_OUT);//设置管脚方向if (ret != HI_ERR_SUCCESS){printf("===== ERROR ===== gpio -> hi_gpio_set_dir1 ret:%d\r\n", ret);return;}printf("----- gpio set dir success! -----\r\n");hi_gpio_set_ouput_val(HI_GPIO_IDX_14, HI_GPIO_VALUE1); //初始化输出高电平
}

定时器延时函数及回调中断

static hi_void hrtimer_callback(hi_u32 data)
{block_or_go_on = 0;
}
void hr_delay(hi_u32 time)int ret;ret = hi_hrtimer_start(rx_timer, time, hrtimer_callback, go_on);if (ret != 0){printf("-----hi timer faild-----\r\n");}printf("block_or_go_on:%d\r\n", block_or_go_on);while (block_or_go_on);block_or_go_on = 1;
}

停止函数

void stop_function(void)
{hi_hrtimer_start(g_hrtim, (time_), hrtimer_callback, go_on);//开启定时器APIio_uart_tx(1);while (!block_or_go_on);block_or_go_on = 1;
}

开始函数

void start_function(void)
{hi_hrtimer_start(g_hrtim, (time_), hrtimer_callback, go_on);//开启定时器API io_uart_tx(0);while (!block_or_go_on);block_or_go_on = 1;
}

主函数:

#define time_ (100)
#define block 0
#define go_on 1main()
{#define time_ (100)
static volatile char block_or_go_on = 1;
int ret = 0;int i = 0;char data;hi_u32 g_hrtim;char b[] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};io_uart_tx_init();io_hrtimer_init(&g_hrtim);for (;;){printf("---has enter TX----\r\n");for (ret = 0; ret < 100; ret++)//发送100个数据,查看是否有误{data = b[ret];start_function();for (i = 0; i < 8; i++){hi_gpio_set_ouput_val(HI_GPIO_IDX_14, data & 0x01);//发送数据APIhr_delay(time_ - 5);data >>= 1;}stop_function();}hr_delay(2000000);}}

这里要说明的是,我将开始位和一定的延时组合到一起,停止位亦如此,数据位后加延时,共同组成整个时序。写好之后数据一般都不对,我们可以用串口软件接收,看收到的数据,因为程序运行需要时间,所以一般都不是104us,我调出来是100us,还得根据自身的情况更改,代码框架是ok的。

串口接收(依旧9600)

思路:开启定时中断,进入中断后关闭中断,在中断函数内进行高低电平判断,将这些bit存储最后转换成需要的数据,也就是说,一个中断函数,完成一个字节的接收!
定时器初始化及中断

static hi_void hrtimer_callback(hi_u32 data)
{block_or_go_on = 0;
}
void io_hrtimer_init(hi_u32 *g_hrtimer)
{hi_u32 ret;/* create timer handle */ret = hi_hrtimer_create(g_hrtimer);if (ret != HI_ERR_SUCCESS){printf("=====ERROR===== hrtimer handle create ret is: %d !!\r\n", ret);return;}printf("----- hrtimer handle create success -----\n");
}

GPIO中断初始化及中断函数:看注释

static volatile hi_u32 irq_flag=0;
static void irq_function(hi_void *arg)
{hi_gpio_deinit();irq_flag = 1;printf("-----has enter irq_function-----\r\n");
}
void gpio_rx_irq_init(void)
{hi_u32 ret;ret = hi_gpio_init(); //注意,该接口不支持重复调用,只能在初始化阶段调用一次//irq_flag = ret;if (ret != HI_ERR_SUCCESS){printf("===== ERROR ===== gpio -> hi_gpio_init ret:%d\r\n", ret);return;}printf("----- gpio init success-----\r\n");ret = hi_gpio_set_dir(HI_GPIO_IDX_5, HI_GPIO_DIR_IN);//方向if (ret != HI_ERR_SUCCESS){printf("===== ERROR ===== gpio -> hi_gpio_set_dir ret:%d\r\n", ret);return;}printf("----- dir init success-----\r\n");ret = hi_io_set_func(HI_GPIO_IDX_5, HI_IO_FUNC_GPIO_5_GPIO);//复用if (ret != HI_ERR_SUCCESS){printf("===== ERROR ===== gpio -> hi_io_set_func ret:%d\r\n", ret);return;}printf("----- io set func success-----\r\n");ret = hi_gpio_register_isr_function(HI_GPIO_IDX_5, HI_INT_TYPE_EDGE, HI_GPIO_EDGE_FALL_LEVEL_LOW, irq_function, 0); //开启中断功能if (ret != HI_ERR_SUCCESS){printf("===== ERROR ===== gpio -> hi_gpio_register_isr_function ret:%d\r\n", ret);return;}printf("----- func init success-----\r\n");
}

主函数

#define _time_ (100)
#define BIT(x) (0x01<<(x))
#define block 0
#define go_on 1
main()
{hi_u32 rx_timer;io_hrtimer_init(&rx_timer); //定时器初始化gpio_rx_irq_init();for (;;){if (irq_flag == 1){int ret = 0;int electric_level[3] = {0};int bit_value;char data = 0;for (ret = 0; ret < 10; ret++)//数据位+停止位+开始位=10{hi_hrtimer_start(rx_timer, (_time_ - 8), hrtimer_callback, go_on);//进行了时间数据的微调while (block_or_go_on);block_or_go_on = 1;hi_gpio_get_input_val(HI_GPIO_IDX_5, &bit_value);if (ret == 8) //第九位停止位为1{printf("4\r\n");break;}if (bit_value == 1){data |= BIT(ret);printf("1\r\n");}else{printf("0\r\n");}block_or_go_on = 1;//置1}printf("%02X ", data);irq_flag = 0;//中断标志位置1hi_gpio_init();//开启中断}}
}

这里我只是给出一个代码框架,细节问题还需要自己去调整,不能做到都copy就ok,为什么这次不在中断里做处理,因为我用的这个IC的GPIO和定时器中断的优先级是相同的,且无法修改。
以上的正确接收的time时间我是试的,就只会在104的周围,还看你的代码的简化程度!

GPIO口模拟串口发送接收(基于H861)相关推荐

  1. linux gpio 模拟串口,STM32的GPIO口模拟串口通信.rar

    [实例简介] 利用GPIO.EXTI外部中断.TIM定时器实现URAT串口,该例子来自21IC网,未做改动,明天自己调试,看看效果 完全是根据UART协议编写 [实例截图] [核心代码] STM32的 ...

  2. 51单片机模拟串口发送接收数据(不使用SBUF)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 51单片机.模拟串口.串口发送.串口接收.逻辑分析仪 前言 一.配置定时器 二.串口发送 三.串口接收 四.主函数 五.波形图 5.1 ...

  3. 用GPIO口模拟串口通信,它真的来了

    你是否遇到过某个MCU串口不够的情况? 这时我们可以考虑用GPIO去模拟,如何具体实现呢? 首选我们需要了解串口的传输协议, UART使用异步模式工作,不需要时钟信号,其一般格式为:起始位+数据位+校 ...

  4. STM32 IO口模拟串口通讯

    转自:http://ziye334.blog.163.com/blog/static/224306191201452833850647 前阵子,调项目时需要用到低波特率串口通讯(300的波特率),才发 ...

  5. 单片机IO口模拟串口程序(发送+接收

    单片机IO口模拟串口程序(发送+接收)[转] qcmc 发表于 - 2011-6-23 0:42:00 前一阵一直在做单片机的程序,由于串口不够,需要用IO口来模拟出一个串口.经过若干曲折并参考了一些 ...

  6. 串口发送程序linux,单片机IO口模拟串口程序(发送+接收

    前一阵一直在做单片机的程序,由于串口不够,需要用IO口来模拟出一个串口.经过若干曲折并参考了一些现有的资料,基本上完成了.现在将完整的测试程序,以及其中一些需要总结的部分贴出来. 程序硬件平台:11. ...

  7. STM8学习笔记----普通IO口模拟串口功能

    串口在产品应用中很常见,但是单片机的默认带的串口往往比较少,有时候就会出现串口不够用,所以就想着能不能用普通IO口模拟串口来实现串口的功能. 要模拟串口首先要清楚串口数据传输过程中的原理. 常用的串口 ...

  8. GPIO口模拟I2C操作

    /*         作者:天空         日期:2014.5.12         功能:利用GPIO口模拟I2C总线,对传感器寄存器读取数据         注意:如果需要移植些文件到其他设 ...

  9. STM32—USART串口发送+接收

    STM32-USART串口发送+接收 本文来自于<STM32--江科大>的笔记整理. 文章目录 STM32-USART串口发送+接收 10.3 串口发送 串口调试助手 10.3.1 数据模 ...

最新文章

  1. 服务器空闲搭建什么网站,空闲的云服务器可以干什么
  2. 镜头视场角计算工具_什么是变焦镜头 变焦镜头介绍【详解】
  3. pg_dump 详解/使用举例
  4. 基于.NET的图表控件解决方案
  5. java类的两个基本成分_Java类文件的基本结构
  6. 2019,从刷新你的运营知识库开始!
  7. java基础之设计模式
  8. 《Python编程从入门到实践》记录之input()函数
  9. 数字ToString作为货币显示并且带小数
  10. java 线程内存模型_JAVA内存模型与线程
  11. C#调用Dephi接口方法
  12. WebSocket 对象简介
  13. 华为荣耀4X的ROOT
  14. 一个c语言程序多个源文件,链接多个C源文件
  15. 浅谈SRAM与DRAM的异同
  16. opencv 手选roi区域_【opencv学习笔记六】图像的ROI区域选择与复制
  17. Qt编写安防视频监控系统56-数据库分页
  18. React native大版本迭代信息记录
  19. python doc2 —— MPI多线程并行计算工具mpi4py
  20. 使用ffmpeg把mp4与m3u8相互转换的操作

热门文章

  1. CAD在线转换PDF格式怎么操作?
  2. 前端浏览器内存监控方式
  3. 服务器——购买云服务器
  4. 软件测试----性能测试
  5. ZMY_异步任务抽象类
  6. du 只查看当前一层目录的大小
  7. 手机用计算机怎么弄平方,手机计算器平方怎么按
  8. 弹性系数系数在水文气象中的应用及其MATLAB实现
  9. linux中运行c找不到conio.h,Linux 下没有conio.h 已解决(示例代码)
  10. WebView实现长按保存图片 长按识别二维码,看完吊打面试官