当前位置: 首页 > news >正文

企业移动网站品牌c2c网站功能

企业移动网站品牌,c2c网站功能,网站维护是做什么的,网站登陆界面怎么做文章目录 一、简介1.串口发送模式2.串口接收模式 二、串口配置三、串口发送四、串口接收 一、简介 本文主要阐述STM32串口的几种工作中使用的工作模式和编程思路。串口通常情况下使用的是#xff1a;1个起始位#xff0c;8个数据位#xff0c;无奇偶校验#xff0c;1位停止… 文章目录 一、简介1.串口发送模式2.串口接收模式 二、串口配置三、串口发送四、串口接收 一、简介 本文主要阐述STM32串口的几种工作中使用的工作模式和编程思路。串口通常情况下使用的是1个起始位8个数据位无奇偶校验1位停止位每传输1个字节的数据相当于传输10bit在波特率9600的情况下1字节需要1.04ms如果传输波特率115200传输1字节数据需要0.087ms。 1.串口发送模式 串口发送方式主要分为3种轮询、中断、DMA发送。下面简述一下各个模式优缺点 模式优点缺点轮询代码最简单会导致代码阻塞会被任何中断在带os的系统中还容易被高优先级任务打断中断将发送优先级提高到该串口中断级别不会被任务打断只会被更高优先级中断打断占用cpu和中断DMA不需要cpu参与数据发送发送也不会被打断代码复杂 1轮询发送   轮询发送是将需要发送的数据写到串口的数据DR寄存器中然后通过循环等待发送完成TC标致位置位判断数据是否发送结束。一般串口在115200波特率下发送1字节数据时间大概0.087ms在没有os的情况下程序需要阻塞89ms只会被中断打断。在有os的情况下还需要考虑到任务切换和高优先级任务的使用串口发送的一包数据就会是断断续续的时间更长。 2中断发送   中断发送是对轮询发送的一种改进其目的是连续发送一包数据不被低优先级中断和任务打断。其思路是开启串口发送中断在应用层调用驱动层发送函数时将中断发送标志位置1/或直接发送第一字节触发串口中断在中断中发送剩余数据。期间每次传输完成时进一次中断其余时间cpu可以运行别的任务而且减少了查询发送完成标志位的时间。对于没有os的系统来说做到了时间片处理非阻塞发送。 3DMA发送   该模式需要根据手册提前配置DMA通道模式等信息通过HAL库提供的发送函数DMA会自动将内存中的参数搬运到串口外设中CPU执行完发送命令就可以执行别的任务了。在dma发送结束时会产生DMA中断告诉用户数据是否发送结束。 2.串口接收模式 串口接收也有轮询模式主要是中断和DMA的方式。下面简述一下各个模式优缺点 模式优点缺点中断代码简单需要多次进入中断DMA不需要cpu参与每字节接收仅产生少量的中断需要配合空闲中断处理 1中断接收   中断接收是一种常见的接收方式适合波特率较低9600或任务不复杂的情况下使用。9600传输数据时使用串口中断接收数据大约1.04ms进一次中断在要求不高的情况下使用中断接收也能满足设计要求尤其对裸机基于时间片的代码框架来说影响不大代码也简洁。但是随着波特率的提高此方法则不太适用当波特率很高115200以上若使用串口中断接收意味着每87us会进入一次中断那么对主程序的时间片影响将会很大故推荐使用DMA。 2DMA接收空闲中断接收   需要提前配置DMA通道DMA模式使用DMA搬运数据串口空闲中断判断驱动层的帧结束。当空闲中断产生时将DMA映射的数据拷贝到应用层的接收缓存区。与中断接收区别是不用每个字节进入一次中断拷贝数据也是将一帧数据拷贝到缓存区。发送1K数据则会在89ms内进1000次中断若再提高波特率对裸机时间片的系统来说影响就很大了。 二、串口配置 UARTUniversal Asynchronous Receiver/Transmitter通用异步收发传输器UART 作为异步串口通信协议的一种工作原理是将传输数据的每个字符一位接一位地传输是在应用程序开发过程中使用频率最高的数据总线。 RT-Thread串口配置步骤 1通过串口名字找到串口句柄 #define SAMPLE_UART_NAME uart2static rt_device_t serial; serial rt_device_find(SAMPLE_UART_NAME);2配置串口参数 使用rt_device_control()函数修改串口配置参数 /* 初始化配置参数 */ struct serial_configure uart2_config RT_SERIAL_CONFIG_DEFAULT; /* step2修改串口配置参数 */ uart2_config.baud_rate BAUD_RATE_115200; //修改波特率为 9600 uart2_config.data_bits DATA_BITS_8; //数据位 8 uart2_config.stop_bits STOP_BITS_1; //停止位 1 uart2_config.bufsz 128; //修改缓冲区 buff size 为 128 uart2_config.parity PARITY_NONE; //无奇偶校验位rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, uart2_config);3设置串口接收回调函数 当发生中断接收中断或者空闲中断时会调用注册的回调函数。用户可以在回调函数中写一些无阻塞的功能。虽然回调函数是在中断中执行所以不能有阻塞和延时。 /* 接收数据回调函数 */ static rt_err_t uart_input(rt_device_t dev, rt_size_t size) {/* 串口接收到数据后产生中断调用此回调函数然后发送接收信号量 */rt_sem_release(rx_sem);cnt;return RT_EOK; }/* 设置接收回调函数 */ rt_device_set_rx_indicate(serial, uart_input);4打开串口设备 打开设备时可以对串口的模式进行配置rt-thread提供三种模式中断模式、轮询模式、DMA 模式。发送和接收只能从中选一个发送和接收可以配置的不一致。默认使用中断接收和轮询发送。 /* 以中断接收及轮询发送模式打开串口设备 */ rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)oflag支持模式参数为下列几个 #define RT_DEVICE_FLAG_INT_RX 0x100 /** INT mode on Rx 中断接收 */ #define RT_DEVICE_FLAG_DMA_RX 0x200 /** DMA mode on Rx DMA接收 */ #define RT_DEVICE_FLAG_INT_TX 0x400 /** INT mode on Tx 中断发送 */ #define RT_DEVICE_FLAG_DMA_TX 0x800 /** DMA mode on Tx DMA接收 */rt_device_open函数中初始化DMA模式会进行参数检查需要确认使用串口DMA宏被定义。如BSP_UART2_RX_USING_DMA否则会rt_serial_open()返回错误。当对应串口DMA宏在rtconfig.h中被定义后通过宏定义设置到对应串口对象的uart_dma_flag参数中在串口初始化阶段通过rt_hw_usart_init()中的rt_hw_serial_register()函数会把对应uart_dma_flag设置到串口dev-flag中后续串口open时只是检查一下参数。 完整的串口配置例程代码如下 /** 程序清单这是一个 串口 设备使用例程* 例程导出了 uart_sample 命令到控制终端* 命令调用格式uart_sample uart2* 命令解释命令第二个参数是要使用的串口设备名称为空则使用默认的串口设备* 程序功能通过串口输出字符串hello RT-Thread!然后错位输出输入的字符 */ #include rtthread.h #include module_uart.h #include drv_usart.h#define SAMPLE_UART_NAME uart2/* 初始化配置参数 */ struct serial_configure uart2_config RT_SERIAL_CONFIG_DEFAULT; /* 用于接收消息的信号量 */ static struct rt_semaphore rx_sem; static rt_device_t serial; uint16_t cnt 0;/* 接收数据回调函数 */ static rt_err_t uart_input(rt_device_t dev, rt_size_t size) {/* 串口接收到数据后产生中断调用此回调函数然后发送接收信号量 */rt_sem_release(rx_sem);cnt;return RT_EOK; }static void serial_thread_entry(void *parameter) {char ch;while (1){/* 从串口读取一个字节的数据没有读取到则等待接收信号量 */while (rt_device_read(serial, -1, ch, 1) ! 1){/* 阻塞等待接收信号量等到信号量后再次读取数据 */rt_sem_take(rx_sem, RT_WAITING_FOREVER);}/* 读取到的数据通过串口输出 */rt_device_write(serial, 0, ch, 1);} }int uart2_init(void) {rt_err_t ret;/* 查找系统中的串口设备 */serial rt_device_find(SAMPLE_UART_NAME);if (!serial){rt_kprintf(find %s failed!\n, SAMPLE_UART_NAME);return RT_ERROR;}/* step2修改串口配置参数 */uart2_config.baud_rate BAUD_RATE_115200; //修改波特率为 9600uart2_config.data_bits DATA_BITS_8; //数据位 8uart2_config.stop_bits STOP_BITS_1; //停止位 1uart2_config.bufsz 128; //修改缓冲区 buff size 为 128uart2_config.parity PARITY_NONE; //无奇偶校验位rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, uart2_config);/* 初始化信号量 */rt_sem_init(rx_sem, rx_sem, 0, RT_IPC_FLAG_FIFO);/* 以中断接收及轮询发送模式打开串口设备 */rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);/* 设置接收回调函数 */rt_device_set_rx_indicate(serial, uart_input);/* 创建 serial 线程 */rt_thread_t thread rt_thread_create(serial, serial_thread_entry, RT_NULL, 1024, 25, 10);/* 创建成功则启动线程 */if (thread ! RT_NULL){rt_thread_startup(thread);}else{ret RT_ERROR;}return ret; } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(uart_sample, uart device sample);三、串口发送 串口的三种发送轮询、中断、DMA发送。下面是发送程序对应用层的接口 rt_size_t rt_device_write(rt_device_t dev,rt_off_t pos,const void *buffer,rt_size_t size) 里面本质上会调用rt_serial_write()函数往串口设备写数据里面又细分了三个函数_serial_int_tx()中断发送 _serial_dma_tx()dma发送_serial_poll_tx()轮询发送。 1.轮询发送 轮询发送是最简单的发送模式rt-thread提供的是阻塞的发送函数。程序会将需要发送的数据一字节一字节的写到串口的DR寄存器然后查询发送完成标志直到数据完全发送结束。优点程序简单易懂缺点浪费cpu资源容易被高优先级任务打断一帧数据发送断断续续的。 _serial_poll_tx()的具体实现每次发送1字节数据循环length长度 rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length) {int size;RT_ASSERT(serial ! RT_NULL);size length;while (length){serial-ops-putc(serial, *data); data;-- length;}return size - length; }putc函数的实现根据单片机型号将数据写入DR或者TDR寄存器中然后等待发送完成标志。按照这种方式代码需要在这阻塞到一帧数据完全发送结束才会执行后面的代码。再此期间代码会被高优先级任务和中断打断。 static int stm32_putc(struct rt_serial_device *serial, char c) {struct stm32_uart *uart;RT_ASSERT(serial ! RT_NULL);uart rt_container_of(serial, struct stm32_uart, serial);UART_INSTANCE_CLEAR_FUNCTION((uart-handle), UART_FLAG_TC); #if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) \|| defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32L5)\|| defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) ||defined(SOC_SERIES_STM32F3)\|| defined(SOC_SERIES_STM32U5)uart-handle.Instance-TDR c; #elseif(uart-config-is485){HAL_GPIO_WritePin(uart-config-de_port,uart-config-de_pin, GPIO_PIN_RESET);}uart-handle.Instance-DR c; #endifwhile (__HAL_UART_GET_FLAG((uart-handle), UART_FLAG_TC) RESET);if(uart-config-is485){HAL_GPIO_WritePin(uart-config-de_port,uart-config-de_pin, GPIO_PIN_SET);}return 1; }2.中断发送 与轮询发送区别是多了一个等待完成信号量的内容。bug是里面字符发送函数与轮询发送函数一样永远返回1所以等待完成函数不会被触发。 rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length) {int size;struct rt_serial_tx_fifo *tx;RT_ASSERT(serial ! RT_NULL);size length;tx (struct rt_serial_tx_fifo*) serial-serial_tx;RT_ASSERT(tx ! RT_NULL);while (length){if (serial-ops-putc(serial, *(char*)data) -1){rt_completion_wait((tx-completion), RT_WAITING_FOREVER);continue;}data ; length --;}return size - length; }3.DMA发送 rt_data_queue_push将数据放入dma数据队列中这里需要特别注意一下直接是应用层写的数据没有发送缓存区若是局部变量在dma发送是可能已经释放掉无法发送正确数据。其次在发送过程中修改应用层数据dma会直接发送修改后的数据这点也需要特别注意。 serial-ops-dma_transmit(serial, (rt_uint8_t *)data, length, RT_SERIAL_DMA_TX)在函数指针背后调用的是对hal库分装一层的dma传输函数。 HAL_UART_Transmit_DMA()是个无阻塞函数也就是执行完这一行时数据开始发送但是不会等到数据完全发送结束。 rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length) {rt_base_t level;rt_err_t result;struct rt_serial_tx_dma *tx_dma;tx_dma (struct rt_serial_tx_dma*)(serial-serial_tx);result rt_data_queue_push((tx_dma-data_queue), data, length, RT_WAITING_FOREVER);if (result RT_EOK){level rt_hw_interrupt_disable();if (tx_dma-activated ! RT_TRUE){tx_dma-activated RT_TRUE;rt_hw_interrupt_enable(level);/* make a DMA transfer */serial-ops-dma_transmit(serial, (rt_uint8_t *)data, length, RT_SERIAL_DMA_TX);}else{rt_hw_interrupt_enable(level);}return length;}else{rt_set_errno(result);return 0;} }static rt_size_t stm32_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction) {if (RT_SERIAL_DMA_TX direction){if (HAL_UART_Transmit_DMA(uart-handle, buf, size) HAL_OK){return size;}else{return 0;}}return 0; }void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma) {/* Transfer Complete Interrupt management ***********************************/else if (((flag_it (DMA_FLAG_TC1 hdma-ChannelIndex)) ! RESET) ((source_it DMA_IT_TC) ! RESET)){if((hdma-Instance-CCR DMA_CCR_CIRC) 0U){/* Disable the transfer complete and error interrupt */__HAL_DMA_DISABLE_IT(hdma, DMA_IT_TE | DMA_IT_TC); /* Change the DMA state */hdma-State HAL_DMA_STATE_READY;}/* Clear the transfer complete flag */__HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));/* Process Unlocked */__HAL_UNLOCK(hdma);if(hdma-XferCpltCallback ! NULL){/* Transfer complete callback */hdma-XferCpltCallback(hdma);}} }四、串口接收 串口接收常见的分中断接收和DMA接收。在RTT串口配置中设置了一个ringbuf其作用是用来接收数据的。无论使用中断接收还是DMA接收数据都会存入ringbuf中。 1.中断接收 在RTT中中断接收的流程如下 中断接收无论如何都会触发单片机中断向量表中的中断函数只需要去查找中断函数中具体实现即可。如果是接收中断则进入rt_hw_serial_isr函数否则则去清除一些错误标志位。 void USART2_IRQHandler(void) {/* enter interrupt */rt_interrupt_enter();uart_isr((uart_obj[UART2_INDEX].serial));/* leave interrupt */rt_interrupt_leave(); }static void uart_isr(struct rt_serial_device *serial) {.../* UART in mode Receiver -------------------------------------------------*/if ((__HAL_UART_GET_FLAG((uart-handle), UART_FLAG_RXNE) ! RESET) (__HAL_UART_GET_IT_SOURCE((uart-handle), UART_IT_RXNE) ! RESET)){rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);} ...else{if (__HAL_UART_GET_FLAG((uart-handle), UART_FLAG_ORE) ! RESET){__HAL_UART_CLEAR_OREFLAG(uart-handle);}if (__HAL_UART_GET_FLAG((uart-handle), UART_FLAG_NE) ! RESET){__HAL_UART_CLEAR_NEFLAG(uart-handle);}if (__HAL_UART_GET_FLAG((uart-handle), UART_FLAG_FE) ! RESET){__HAL_UART_CLEAR_FEFLAG(uart-handle);}if (__HAL_UART_GET_FLAG((uart-handle), UART_FLAG_PE) ! RESET){__HAL_UART_CLEAR_PEFLAG(uart-handle);}} }rt_hw_serial_isr()可以分成两部分读取数据和回调函数调用部分。读取数据部分是负责把串口接收数据读取到ringbuf中。 while (1) {ch serial-ops-getc(serial);if (ch -1) break;/* disable interrupt */level rt_hw_interrupt_disable();rx_fifo-buffer[rx_fifo-put_index] ch;rx_fifo-put_index 1;if (rx_fifo-put_index serial-config.bufsz) rx_fifo-put_index 0;/* if the next position is read index, discard this read char */if (rx_fifo-put_index rx_fifo-get_index){rx_fifo-get_index 1;rx_fifo-is_full RT_TRUE;if (rx_fifo-get_index serial-config.bufsz) rx_fifo-get_index 0;_serial_check_buffer_size();}/* enable interrupt */rt_hw_interrupt_enable(level); }上述使用serial-ops-getc(serial)函数看这个名字就能猜到是获取串口接收的一个字节数据。对于STM32来说就是将串口的DR寄存器通过这个函数返回。将DR寄存器中的值存入ringbuf还对ringbuf满的情况做了一下异常处理ringbuf is_full标志位会置一数据会覆盖最早的数据导致数据丢失所以需要保证应用层及时从ringbuf中取出数据。 static int stm32_getc(struct rt_serial_device *serial) {int ch;struct stm32_uart *uart;RT_ASSERT(serial ! RT_NULL);uart rt_container_of(serial, struct stm32_uart, serial);ch -1;if (__HAL_UART_GET_FLAG((uart-handle), UART_FLAG_RXNE) ! RESET){...ch uart-handle.Instance-DR stm32_uart_get_mask(uart-handle.Init.WordLength, uart-handle.Init.Parity);...}return ch; }再看看回调函数部分若回调函数不为空且这次就收到数据则调用一次接收回调函数。通常回调函数中释放一个信号量通知应用层程序从ringbuf中读取数据。其实这也看出了中断方式的一个缺陷每接收一字节放一次ringbuf调用一次回调函数应用层也只能一字节一字节接收。为了减CPU的使用率还提供了DMA的方式。 /* 调用回调函数部分 */ /* invoke callback */ if (serial-parent.rx_indicate ! RT_NULL) {rt_size_t rx_length;/* get rx length */level rt_hw_interrupt_disable();rx_length (rx_fifo-put_index rx_fifo-get_index)? (rx_fifo-put_index - rx_fifo-get_index):(serial-config.bufsz - (rx_fifo-get_index - rx_fifo-put_index));rt_hw_interrupt_enable(level);if (rx_length){serial-parent.rx_indicate(serial-parent, rx_length);} } break;2.DMA接收 这里触发串口中断的判断变了变成了DMA半满、满中断和空闲中断触发串口中断三者是或的关系。接收中断中如果开启DMA则会执行以下代码 else if ((uart-uart_dma_flag) (__HAL_UART_GET_FLAG((uart-handle), UART_FLAG_IDLE) ! RESET) (__HAL_UART_GET_IT_SOURCE((uart-handle), UART_IT_IDLE) ! RESET)){level rt_hw_interrupt_disable();recv_total_index serial-config.bufsz - __HAL_DMA_GET_COUNTER((uart-dma_rx.handle));recv_len recv_total_index - uart-dma_rx.last_index;uart-dma_rx.last_index recv_total_index;rt_hw_interrupt_enable(level);if (recv_len){rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len 8));}__HAL_UART_CLEAR_IDLEFLAG(uart-handle);}else if (__HAL_UART_GET_FLAG((uart-handle), UART_FLAG_TC) (__HAL_UART_GET_IT_SOURCE((uart-handle), UART_IT_TC) ! RESET)){if ((serial-parent.open_flag RT_DEVICE_FLAG_DMA_TX) ! 0){HAL_UART_IRQHandler((uart-handle));}UART_INSTANCE_CLEAR_FUNCTION((uart-handle), UART_FLAG_TC);}DMA在处理的过程中也是调用rt_hw_serial_isr与中断一致接收长度需要根据DMA接收长度增加个小计算得出。后续处理与中断接收也基本一致将数据更新进ringbuf再调用回调函数。最大的区别是DMA一次会接收一帧或者半帧数据才进一次中断。回调函数处理也会有所不一样官方例程也不在释放信号量了通过消息队列传出串口接收数据大小交给应用层处理。
http://www.hkea.cn/news/14407482/

相关文章:

  • 免费做二建题的网站计算机哪方面技术吃香
  • 苏州网络推广苏州网站建设网站建设项目报价
  • 网站制作建立速橙科技有限公司网站建设
  • 做视频编辑哪个网站素材比较好装修设计公司网站排名
  • 做地方网站需要什么部门批准网站的公司
  • 全国网站排名新材建设局网站
  • 中国建设银行的网站特色双wan路由器做网站接入
  • 做肯德基玻璃门网站兰州网站设计
  • 杭州市上城区建设局网站wordpress rclean
  • 可以发布广告的网站郑州企业管理培训课程
  • 灰色网站欣赏英雄联盟最新赛事
  • 网站建设网站推广买服务器做网站
  • 如何做产品展示网站中国建筑网官网手机版
  • 千图主站的功能介绍动态可视化wps图表制作
  • 医疗器械查询官网南京网络推广优化哪家好
  • 2016企业网站建设合同wordpress双语安装
  • 怎么关键词优化网站山西孝义网站开发
  • 建设电商网站的个人心得网站建设与管理教学大纲
  • 为什么买的网站模版不好用网红营销套路
  • 郑州云拓网站建设公司wordpress钩子自定义钩子
  • 个人网站免费的吗网页设计图片的代码
  • 广州广州网站建设公司网站域名到期查询
  • 网站推广的主要方法重庆网站建设去迅法网
  • 怎么管理网站添加代码威海制作网站
  • 青岛建网站公司哪家专业设计网站需要多少钱
  • 网站维护要求网站开发工作描述
  • 仿站小工具wordpress网站推广公司
  • 做网站用那一种语言最好品牌网站制作报价表
  • 问卷调查网站哪个好自己电脑做服务器上传网站 需要备案吗
  • 公众号平台登陆入口seo在线教程