tag 标签: usart

相关博文
  • 热度 25
    2015-4-4 17:39
    2279 次阅读|
    0 个评论
    rt_thread的finsh shell系统不愧是调试的一项利器,它可以除了完成一般shell的功能外,甚至还可以自定义命令。这个对功能单一的嵌入式系统来说是十分可贵的。在此我并不想对finsh shell具体有哪些功能再多做赘述,这些都可以在rt_thread的官方文档上找到,我主要想说明的是finsh shell完成功能的这个大致的过程。      finsih shell的底层部分是usart,具体是又那个usart口完成就靠finsh_set_device指定。本人的硬件平台是stm32f103ze,这里rt_thread使用的是usart1,可能是考虑到调试时候的方便,usart1正好也是控制台的输出口。虽然有两套系统使用usart1,但基于rt_thread的驱动机制,这两者是不会冲突的。现在我来说明uasrt驱动是如何在rt_thread里完成注册、初始化以及顺利使用的。   不同于其他驱动,usart的驱动开始的相当早,在中断、时钟、FSMC的之后就轮到它初始化了。毕竟usart承担着系统控制台的输出的任务,只有在它完成后,系统之后的信息才能被打印在终端上,之后所遇到的问题才能显现出来,因此能够越早启动uasrt自然是越好的。     在stm32的平台上rt_thread使用的是usart1,关于其硬件配置和stm32一般配置相同于,不再赘述,我们关注的是usart1是如何与rt_thread联系起来的。在此之前先介绍rt_thread的驱动的核心rt_device结构体。      调用rt_hw_serial_register之后,rt_device以rt_object的形式被rt_thread组织起来,在后面我们可以很方便的通过rt_device_find利用之前注册的名字来找到相应的设备,事实是之后看见的finsh_set_device函数就是这么做的。而flag和通用接口函数可以连接上层和底层,完成相应的设备操作。rx_indiacate和tx_complete同样也是联系上下层的接口,但与前者是完成上层到底层操作不同的是,它们是通过中断调用向上层传递特定的信息。最后private是存放设备私有变量的地方,之前的部分还是rt_thread通用的架构,而private则是对于底层特定操作或是存放特定数据的地方,熟悉linux内核的同学一定对这种结构的形式非常熟悉,因为在内核特别是在驱动中这是经常使用的手段。      rt_hw_serial_register之后,usart1在硬件上已经配置好了,设置为正常的发送和中断的接受,而且已经把其注册塞入rt_thread的核心object的管理架构中了。但是我们此时还是没有完成usart的设备的初始化,毕竟private部分,我们还没有配置呢。     之后系统会将所有注册的设备都初始化一边,调用的是rt_device-init函数,对于usart1,就是rt_serial_init,它来完成我们之前没有完成的private部分的设置了。由于usart1没有使用dma发送,唯一需要配置的就是int_rx部分。uasrt1是采用中断接受的方式,像大多数操作系统一样,需要在底层设立专门的数据缓存区,方便上层以同步或是异步的方式进行读写。这里int_rx采用的是典型的环形缓存区。       在usart接受中断调rt_hw_serial_isr,获取一个数据save_index加1,而上层调rt_serial_read读取串口数据,读取一个read_index加1,两者一旦到达边界就回到数据区头。一旦read_index=save_index就认为环形缓存区数据已经取空,而save_index=read_index-1的时候则认为缓存区已满。针对缓存已满的情况下,save_index和read_index同时加1,相当于丢弃了最老的数据。usart中断是随时可能发生的,上层是如何得知环形缓存区数据更新的呢?之前在rt_device的rx_indicata就起了关键作用,一旦上层某个部分要求串口接收数据,它就会调rt_device_set_rx_indicate,加自己的回调函数赋给rx_indicate,一旦中断发生,接收新数据后,就会调用上层赋给的rx_inidate函数来执行上层的接受操作。在finish shell里我们通过finsh_set_device注册了finsh_rx_ind函数,这个函数完成的功能很简单,就是将全局变量finsih_shell这个结构体里的rx_sem给释放了。具体rt_thread的信号量同步问题,如果要说的就扯的远了,这里就不多说了。只是说下这个操作的结果是唤醒了我们下一篇要讲的finish shell最重要的进程tshell,让它来处理接受的数据。     至于usart1的发送部分,由于没有采用dma模式,rt_serial_write 就非常简单了,也就是最简单的发一个等一个不停的发直到发完为止,实在没什么好说的。而下一篇我将涉及finish非常重要的一个部分“语法解释”,它才是finish shell关键难点之一。 转载自:http://blog.chinaunix.net/xmlrpc.php?r=blog/articleuid=25788300id=3395425
  • 热度 21
    2013-8-23 08:08
    1565 次阅读|
    0 个评论
    用STM32F103C8T6上的PA0,配置成ADC,将模拟量转找成数字量发送到串口。模拟量由一个可调电阻提供。具体的细节后续再整理成文字,这里把实验现象发上来。 AD测得电压值约为2800mV,即2.8V 实测电压值:   再测一组 实测电压值:   总体来说,还算可以吧。没有加任何的数字滤波算法。因为时间问题,先简单记录下,回头有时间了再整理。 附件是工程的代码。
  • 热度 29
    2013-7-6 00:46
    5283 次阅读|
    0 个评论
      前言:         最近项目中需要用到串口及网口输出大量的数据给上位机,先调试串口。发现 CPU 花蛮多时间来传输数据,太浪费了。所以想到了用 DMA 来传输串口数据,一搜资料,库函数里还真的有 DMA 来实现 USART 数据的传输的,真的。遂有以下学习笔记:       我以前使用串口都是简单的通过重构 put char 函数,调用 printf 函数来给上位机 PC 传输数据的,数据格式通常是 ASCII 码,然而这次数据帧格式是十六进制,所以得用 USART_SendData() 函数了,由于数据量大,有 3 000 多字节数据,除了发送数据外, CPU 还得做其他事情,所以这里用 DMA 来传数据。   ( 1 )建立发送数据缓冲区: uint32_t SendBuff ; ( 2 )宏定义串口的 DMA 基地址: #define USART1_DR_Base  0x40013804 ( 3 )开启 USART1 、 GPIOA 、 AFIO 、 DMA1 的时钟,并且初始化 USART 的 GPIO: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);   GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;         //tx GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;   GPIO_Init(GPIOA,GPIO_InitStructure);   GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;          //rx GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA,GPIO_InitStructure);   USART_InitStructure.USART_BaudRate=256000; // 波特率 256000bit/s USART_InitStructure.USART_WordLength=USART_WordLength_8b;        //8 bit data USART_InitStructure.USART_StopBits=USART_StopBits_1;                // stop bit 1 USART_InitStructure.USART_Parity=USART_Parity_No;                        //no  parity bit USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;          // 双工模式 USART_Init(USART1,USART_InitStructure);   ( 4 )使能串口 1 的发送和接收中断;使能串口 1 : //enable USART1's interruput USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //enable USART1 USART_Cmd(USART1,ENABLE);   ( 5 ) USART 中断优先级配置: void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure;     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   NVIC_Init(NVIC_InitStructure); }   ( 6 ) DMA 对 USART1 的配置: void DMA_Configuration(void) {     DMA_InitTypeDef DMA_InitStructure;       DMA_DeInit(DMA1_Channel4);     DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base; // 在( 2 )中已经宏定义了,内存地址 串口数据寄存器地址     DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;            // 要发送的数组,注意此处发送的是 32 位的, 即四个字节的数据。     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;     DMA_InitStructure.DMA_BufferSize = 3000; // 传输数据大小     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA 模式一次传输,不循环     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; // 优先级中     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;     DMA_Init(DMA1_Channel4, DMA_InitStructure); }     ( 7 )主函数: int main(void) {   SystemInit(); USART_Config(); NVIC_Configuration();   DMA_Configuration();   LED_Config();        Data_init();     USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // 将 USART1 配置成 DAM 方式工作,    DMA_Cmd(DMA1_Channel4, ENABLE); // 使能 DMA 通道,开始传输数据       while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET) // 此时 DMA 正在传输数据,传输结束则跳出 while  {      LED1_ON;   // 当 DMA 在传输数据时, CPU 在此可以干其他事情,这里是举例点灯   LED2_OFF;   delay_ms(50);   LED1_OFF;   LED2_ON;   delay_ms(50);    }  printf("\r\nDMA transmission successful!\r\n");    while(1); }   ( 8 )还有 USART 中断尚未弄明白,后续补充。
  • 热度 19
    2013-6-26 20:24
    1231 次阅读|
    0 个评论
    今天讲讲STM32的串口学习。 串口最基本的设置就是波特率的设置。所以在调用STM32的串口功能前要进行设置: 1.开启串口时钟; 2.设置相应的IO口模式; 3.配置波特率、数据位长度、就校验位 每个串口都有一个自己独立的波特率寄存器USART_BRR。 Tx/Rx波特率=fPCLKx/(16*USARTDIV) 同时需要注意的是:USART和GPIO是两种不同的设备,USART是“借用”了GPIO设备作为自己的输出通道,所以在使用串口功能时,不仅要打开USART时钟,而且还要打开相应GPIO的时钟,同时要将对应GPIO引脚设置为第二功能模式。 贴出串口初始化部分代码,大家共享: void uart_init(U32 bound)  { //GPIO端口设置     GPIO_InitTypeDef GPIO_InitStructure;                  //定义GPIO端口初始化结构体 USART_InitTypeDef USART_InitStructure;                //定义USART初始化结构体 NVIC_InitTypeDef NVIC_InitStructure;                  // 定义优先级初始化结构体   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);   //使能USART1、GPIOA时钟,将GPIOA设置为第2功能 //USART1_TX   PA.9     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     GPIO_Init(GPIOA, GPIO_InitStructure);     //USART1_RX  PA.10     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;     GPIO_Init(GPIOA, GPIO_InitStructure);     //Usart1 NVIC 配置     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; //中断优先级:0 1 2 3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 中断响应优先级:0 1 2 3   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器USART1    //USART 初始化设置 USART_InitStructure.USART_BaudRate = bound; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;       USART_Init(USART1, USART_InitStructure);       USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断         USART_Cmd(USART1, ENABLE);                    //使能串口  }    
  • 热度 24
    2013-2-14 23:46
    2496 次阅读|
    0 个评论
    Pin Re-mapping is a simple but important skills in programming STM32. Here shows a simple example to re-map USART1_TX and USART1_RX from PA9, PA10 (not Five-volt tolerant) to PB6, PB7 (Five-volt tolerant) for STM32F103RB. Comparisons between the steps in re-mapping and not re-mapping the pins When PA9, PA10 are used for USART1 i. Turn on Peripheral Clock for GPIOA ii. Config PA9 as Alternate Function Push-pull output, and PA10 as Input Floating iii. Turn on Peripheral Clock for USART1 iv. Config USART1 baud rate and properties... When PB6, PB7 are used for USART1 (Re-mapping) i. Turn on Peripheral Clock for GPIOB ii. Config PA6 as Alternate Function Push-pull output, and PA7 as Input Floating iii. Turn on Peripheral Clock for USART1 iv. Config USART1 baud rate and properties... v. Enable Alternate Function Clock vi. Enable USART1 re-mapping From above, we can see that only two more steps is needed... It is so simple! Sample Coding for re-mapping the USART1: ---------------------------------------------------- GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; /* Turn on periph clock for both GPIOB and USART */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1, ENABLE); /* Config GPIO */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;              GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   GPIO_Init(GPIOB, GPIO_InitStructure);            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;             GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); /* Config USART1 */    USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_ITConfig(USART1, USART_IT_TXE, ENABLE); USART_ClearFlag(USART1,USART_FLAG_TC); USART_Cmd(USART1, ENABLE); /* Re-mapping Config */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO , ENABLE); GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE); ---------------------------------------------------- The peripheral clock command of AFIO can be combined with that of GPIOB and USART1, i.e. the re-mapping only requires only 1 more line of code.
相关资源