摩登3平台登录_STM32如何高效接收串口数据?

目录 USART3_DR的地址 DMA的通道 DMA的中断 USART接收回调函数 头文件源码 DMA的基本配置 环形队列接收数据 函数原型 参考用例 总结 硬件:stm32f103cbt6软件:STM32F10x_StdPeriph_Lib_V3.5.0 DMA,直接内存存取,可以用它的双手释放CPU的灵魂,所以,本文通过USART3进行串口收发,接受使用DMA的方式,无需CPU进行干预,当接受完成之后,数据可以直接从内存的缓冲区读取,从而减少了CPU的压力。 具体的代码实现如下: usart_driver.h  封装了接口,数据接收回调函数类型,基本数据结构等; usart_driver.c  函数原型实现,中断服务函数实现等; 拷贝这两个文件即可,可以根据目录下的参考用例,进行初始化。 头文件usart_driver.h已经声明了外部函数可能用到的接口; USART3_DR的地址 因为USART3接收到数据会存在DR寄存器中,而DMA控制器则负责将该寄存器中的内容一一搬运到内存的缓冲区中(比如你定义的某个数组中),所以这里需要告诉DMA控制去哪里搬运,因此需要设置USART3_DR的总线地址。 USART3的基址如下图所示; USART3的基址 DR寄存器的偏移地址如下图所示; DR偏移地址 所以最终地址为:0x40004800 + 0x004#define USART_DR_Base 0x40004804 DMA的通道 因为有很多外设都可以使用DMA,比如ADC,I2C,SPI等等,所以,不同的外设就要选择属于自己的DMA通道,查找参考手册; DMA通道 因此USART3_RX在这里会使用DMA1的通道3,这都是硬件上已经预先分配好的,我们需要遵循这个规则。所以在代码中我们做出相应的定义;如下所示; #define USART_Rx_DMA_Channel    DMA1_Channel3 DMA的中断 DMA支持三种中断:传输过半,传输完成,传输出错; DMA中断 因此在使用是相当安全也相当灵活,而本文只是用了传输完成中断;如下定义了,传输完成中断的标志位,DMA1_FLAG_TC3也就对应了图中的TCIF; #define USART_Rx_DMA_FLAG       DMA1_FLAG_TC3 USART接收回调函数 在STM32的HAL中封装了大量外设的回调函数,使用起来十分方便,但是标准库中则没有这样的做法,但是这里我们可以自己实现,rx_cbk就是回调,即串口数据接收完成就会执行已经注册的回调函数; typedef void (*rx_cbk)(void* args); 通过使用接口usart_set_rx_cbk进行回调函数的注册,pargs为将传递的参数指针; void usart_set_rx_cbk(uart_mod_t *pmod, rx_cbk pfunc,void *pargs); 头文件源码 #ifndef USART_DRIVER_H#define USART_DRIVER_H#include  #include  /* Private function prototypes -----------------------------------------------*/#define USE_MICROLIB_USART 1#if USE_MICROLIB_USART#ifdef __GNUC__/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf   set to 'Yes') calls __io_putchar() */#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)//#define GETCHAR_PROTOTYPE int fgetc(FILE *f)#endif /* __GNUC__ */extern PUTCHAR_PROTOTYPE;#else#endif //default 8N1#define COM_PORT USART3#define TX_PIN  GPIO_Pin_10#define RX_PIN  GPIO_Pin_11#define BAUDRATE 115200#define IRQ_UART_PRE 3#define IRQ_UART_SUB 3#define USART_Rx_DMA_Channel    DMA1_Channel3#define USART_Rx_DMA_FLAG       DMA1_FLAG_TC3#define USART_DR_Base           0x40004804#define USART_BUF_SIZE   ((uint16_t)16)typedef void (*rx_cbk)(void* args);struct uart_mod {  uint8_t rx_buf[USART_BUF_SIZE]; uint8_t rx_dat_len; uint8_t head; uint8_t tail;   void (*init)(void);  void *pargs; rx_cbk pfunc_rx_cbk;};typedef struct uart_mod uart_mod_t;extern  uart_mod_t user_uart_mod;void usart_init(void);void usart_set_rx_cbk(uart_mod_t *pmod, rx_cbk pfunc,void *pargs);void usart_send_char(char ch);void usart_test_echo(void);uint8_t usart_recv_char(void);int usart_printf(const char *fmt, ...);//extern GETCHAR_PROTOTYPE;#endif DMA的基本配置 串口接收DMA的配置在函数dma_init中; static void dma_init(void) 已经定义了数据缓冲区,如下: uint8_t RxBuffer[USART_BUF_SIZE] = { 0 }; 因此需要在DMA的配置中设置USART_DR的地址,和数据缓冲区的地址,以及两者的大小;还有就是数据流向; 寄存器流向内存; 内存流向寄存器;这个需要搞清楚;相关配置如下所示;  DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_Base; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer;   DMA_InitStructure.DMA_BufferSize = USART_BUF_SIZE; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 注意:DMA_DIR_PeripheralSRC表示,外设作为源地址,数据是从外设寄存器流向内存,即DMA会把数据从地址USART_DR_Base搬运到RxBuffer去。如果这个地方搞错,会导致RxBuffer始终没有你想要的数据。 环形队列接收数据 线性缓冲区会因为缓冲器接收数据已满导致无法继续接收的问题;而环形队列进行接收的话,会自动进行覆盖,这样一来,在读取数据的时候,也要配置一个环形队列进行数据处理,下面的配置是把DMA配置为循环模式; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 在结构体user_uart_mod中,则用两个变量分别指向队首head和队尾tail;具体数据的读取在函数USART3_IRQHandler中,会把数据从内存的RxBuffer读取到结构体user_uart_mod的成员变量rx_buf中;最终调用回调函数。 函数原型 usart_driver.c #include  #include  #include "stm32f10x_usart.h"#include "usart_driver.h"uint8_t RxBuffer[USART_BUF_SIZE] = { 0 };uart_mod_t user_uart_mod = { .rx_dat_len = 0, .head = 0, .tail = 0, .pfunc_rx_cbk = NULL, .pargs = NULL};static USART_InitTypeDef USART_InitStructure;static void rcc_init(void){ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* Enable GPIO clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB        | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART3, ENABLE);}static void gpio_init(void){  GPIO_InitTypeDef GPIO_InitStructure;  /* Configure USART Tx as alternate function push-pull */  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  GPIO_InitStructure.GPIO_Pin = TX_PIN;  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  GPIO_Init(GPIOB, &GPIO_InitStructure);  /* Configure USART Rx as input floating */  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  GPIO_InitStructure.GPIO_Pin = RX_PIN;    GPIO_Init(GPIOB, &GPIO_InitStructure);}static void dma_init(void){  DMA_InitTypeDef DMA_InitStructure;  /* USARTy_Tx_DMA_Channel (triggered by USARTy Tx event) Config */  DMA_DeInit(USART_Rx_DMA_Channel); DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_Base; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer; //DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = USART_BUF_SIZE; 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_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(USART_Rx_DMA_Channel, &DMA_InitStructure);}static void irq_init(void){ NVIC_InitTypeDef NVIC_InitStructure; /* Enable the USART3_IRQn Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = IRQ_UART_PRE; NVIC_InitStructure.NVIC_IRQChannelSubPriority = IRQ_UART_SUB; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);}void usart_send_char(char ch){ /* Loop until the end of transmission */ //while (USART_GetFlagStatus(COM_PORT, USART_FLAG_TC) == RESET){} while((COM_PORT->SR & USART_FLAG_TC) != USART_FLAG_TC){  }  USART_SendData(COM_PORT, (uint8_t) ch);}uint8_t usart_recv_char(){ /* Wait the byte is entirely received by USARTy */    //while(USART_GetFlagStatus(COM_PORT, USART_FLAG_RXNE) == RESET){} while((COM_PORT->SR & USART_FLAG_RXNE) != USART_FLAG_RXNE){  }     /* Store the received byte in the RxBuffer1 */    return (uint8_t)USART_ReceiveData(COM_PORT);}int usart_printf(const char *fmt, ... ){    uint8_t i = 0;    uint8_t usart_tx_buf[128] = { 0 };    va_list ap;    va_start(ap, fmt );    vsprintf((char*)usart_tx_buf, fmt, ap);    va_end(ap);  while(usart_tx_buf[i] && i < 128){  usart_send_char(usart_tx_buf[i]);     i++; }     usart_send_char('\0'); return 0;}void usart_test_echo(){ uint8_t tmp_dat = 0xff; tmp_dat = usart_recv_char(); usart_send_char(tmp_dat);}void usart_init(void){ rcc_init (); gpio_init (); irq_init();  /* USARTx configured as follow:  - BaudRate = 115200 baud    - Word Length = 8 Bits  - One Stop Bit  - No parity  - Hardware flow control disabled (RTS and CTS signals)  - Receive and transmit enabled */ USART_InitStructure.USART_BaudRate = BAUDRATE; 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 configuration */ USART_Init(COM_PORT, &USART_InitStructure); USART_ITConfig(COM_PORT, USART_IT_IDLE, ENABLE); //USART_ITConfig(COM_PORT, USART_IT_RXNE, ENABLE); /* Enable USART */ USART_Cmd(COM_PORT, ENABLE);  USART_DMACmd(COM_PORT,USART_DMAReq_Rx, ENABLE); dma_init(); DMA_ITConfig(USART_Rx_DMA_Channel, DMA_IT_TC, ENABLE);  DMA_ITConfig(USART_Rx_DMA_Channel, DMA_IT_TE, ENABLE); DMA_Cmd(USART_Rx_DMA_Channel, ENABLE); }void usart_set_rx_cbk(uart_mod_t *pmod, rx_cbk pfunc,void *pargs){ pmod->pargs = pargs; pmod->pfunc_rx_cbk = pfunc;}void DMA1_Channel3_IRQHandler(void){     if(DMA_GetITStatus(USART_Rx_DMA_FLAG) == SET){                DMA_ClearITPendingBit(USART_Rx_DMA_FLAG);    }}/**  * @brief  This function handles USART3 global interrupt request.  * @param  None  * @retval None  */void USART3_IRQHandler(void){ uint8_t buf[USART_BUF_SIZE]; uint16_t rect_len = 0; if(USART_GetITStatus(COM_PORT, USART_IT_IDLE) != RESET)  {  uint8_t i = 0;  USART_ReceiveData(COM_PORT);  user_uart_mod.head = USART_BUF_SIZE - DMA_GetCurrDataCounter(USART_Rx_DMA_Channel);    //fifo is not full   while(user_uart_mod.head%USART_BUF_SIZE != user_uart_mod.tail%USART_BUF_SIZE){      user_uart_mod.rx_buf[i++] = RxBuffer[user_uart_mod.tail++%USART_BUF_SIZE];  }  user_uart_mod.rx_dat_len = i;  //DMA_Cmd(USART_Rx_DMA_Channel, ENABLE);  if(user_uart_mod.pfunc_rx_cbk != NULL){   user_uart_mod.pfunc_rx_cbk(user_uart_mod.pargs);  } } USART_ClearITPendingBit(COM_PORT, USART_IT_IDLE); //USART_ClearITPendingBit(COM_PORT, USART_IT_RXNE);}#if USE_MICROLIB_USART/**  * @brief  Retargets the C library printf function to the USART.  * @param  None  * @retval None  */PUTCHAR_PROTOTYPE{ /* Place your implementation of fputc here */ /* e.g. write a character to the USART */ USART_SendData(COM_PORT, (uint8_t) ch); /* Loop until the end of transmission */ while (USART_GetFlagStatus(COM_PORT, USART_FLAG_TC) == RESET) {} return ch;}#else#pragma import(__use_no_semihosting)                          struct __FILE {  int handle; }; FILE __stdout;       int _sys_exit(int x){  x = x;  return 0;} int fputc(int ch, FILE *f){       /* Place your implementation of fputc here */ /* e.g. write a character to the USART */ USART_SendData(COM_PORT, (uint8_t) ch); /* Loop until the end of transmission */ while (USART_GetFlagStatus(COM_PORT, USART_FLAG_TC) == RESET) {} return ch;}#endif 参考用例 这里需要调用usart_init,并设置回调函数,如果不设置,则不会执行回调。 void motor_get_cmd_from_uart(void *pargs){  if(pargs == NULL){  return; }  uart_mod_t *p = pargs; if(p->rx_dat_len > 0 && p->rx_dat_len == PACKAGE_SIZE){  if(p->rx_buf[0] == PACKAGE_HEAD   && p->rx_buf[PACKAGE_SIZE - 1] == PACKAGE_TAIL){   user_cmd_mod.head = p->rx_buf[0];   user_cmd_mod.cmd.value_n[0] = p->rx_buf[1];   user_cmd_mod.cmd.value_n[1] = p->rx_buf[2];      user_cmd_mod.option = p->rx_buf[3];      user_cmd_mod.data.value_n[0] = p->rx_buf[4];   user_cmd_mod.data.value_n[1] = p->rx_buf[5];   user_cmd_mod.data.value_n[2] = p->rx_buf[6];   user_cmd_mod.data.value_n[3] = p->rx_buf[7];      user_cmd_mod.tail = p->rx_buf[PACKAGE_SIZE - 1];   user_cmd_mod.process_flag = 1;  }   } p->rx_dat_len = 0; }int main(void){ usart_init(); usart_set_rx_cbk(&user_uart_mod, motor_get_cmd_from_uart,&user_uart_mod);} 总结 本文简单介绍了基于STM32基于DMA,利用串口空闲中断进行串口数据接收的具体配置和实现方法,代码基于标准库3.5版本;因为标准库ST目前已经不再更新,并且ST提供了cubemx工具可以进行基于HAL库和LL库的外设快速配置,从而简化大量工作;当然为了不掉头发感觉撸寄存器也不错,最终适合自己的才是最好的。 —— The End — — 推荐好文   点击蓝色字体即可跳转  感觉身体被掏空!只因为肝了这篇空间矢量控制算法  我打赌!你还不会UART  PID微分器与滤波器的爱恨情仇  简易PID算法的快速扫盲 增量式PID到底是什么? 三面大疆惨败,因为不懂PID的积分抗饱和 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3测速登录地址_基础知识:压敏电阻原理、参数、选型

周末好~ 压敏电阻并不是一般的电阻,而是一种具有瞬态电压抑制功能的元件,效果同TVS。 这篇文章介绍压敏电阻的一些基本知识,包括参数、选型、应用等。      基础知识   压敏电阻用MY表示,MY后缀:J (家用)、W(稳压)、G(过压)、P (高频)、L(防雷)、H(灭弧)、Z(消噪)等,这是一般通用命名方式,不同厂家的命名不太一样。 压敏电阻是一种具有非线性伏安特性的特殊电阻器件,英文名称叫Voltage Dependent Resistor,简写为VDR ,或者叫做Varistor。 压敏电阻不是真正的电阻,而是一种具有瞬态电压抑制功能的元件,一般无正负极之分,这一点不同于TVS,使用时同样是并接与被保护IC或电路,压敏电阻的响应时间会比TVS慢一点。 当加到压敏电阻上的电压超过一定值时,它的阻值会迅速下降,以导通大电流,保护后端电路;当低于其工作电压时,压敏电阻阻值极高,相当于开路,不影响后端电路的工作状态。 压敏电阻虽然能吸收很大的浪涌能量, 但不能承受毫安级以上的持续电流,在用作过压保护时必须考虑到这一点。 压敏电阻与被保护设备连接 再看一下压敏电阻的参数。    参数解读    如下是某一压敏电阻的电气参数。 某一压敏电阻电气参数 ▉ 压敏电压 指击穿电压或阈值电压,特定电流下测得的压敏电阻两端的电压,一般是1mA直流电流通入压敏电阻时测试得到的。 一般符号是Vb@1mA(DC)或者V1mA。 ▉ 最大工作电压 分为交流和直流两种情况。对交流来说,一般用AC RMS表示,指的是加在压敏电阻上的交流有效值不能超过这个值,上面SPEC的Vwac指加在压敏电阻上的交流电压有效值不能超过4V。对直流来说,被保护信号或者电路的最高电压不能超过这个值。 SPEC中的Vdc是5.5V,即对于即对于5.5V以上的直流电路来说,这个压敏电阻是不合适的。 ▉ 最大钳位电压 指施加规定的脉冲能量波形如(8/20µs)时压敏电阻两端电压,从SPEC看,对压敏电阻施加8/20µs脉冲波形时,最大钳位电压是18V。8/20us脉冲指的是8us达到100%Ipp,20us达到50%Ipp。 8/20µs脉冲能量波形 ▉ 能量耐量 指施加规定的脉冲能量波形(如10/1000µs波形)时压敏电阻吸收的最大能量,符号用E表示,单位是J(焦耳Joule),压敏电阻的片径越大,它的能量耐量越大,耐冲击电流也越大。 能量耐量的计算公式是:W=KIVT,I是流过压敏电阻的峰值电流,K是电流I的波形系数,不同的脉冲波形系数K不一样(2ms的方波K=1,8/20μs的波形K=1.4,10/1000μs的波形K=1.4),T是电流的持续时间,V是电流为I时压敏电阻两端的电压。 10/1000µs脉冲能量波形 ▉ 浪涌电流 指的是施加规定的脉冲能量波形(如8/20µs)时,压敏电阻的电气特性不会下降的最大电流,从SPEC上可以看到此压敏电阻,在8/20µs脉冲波形下,最大浪涌电流到3A。 有这么定义的:1次,以 8/20μs 标准波形的电流作一次冲击的最大电流值,此时压敏电压变化率仍在±10%以内;2 次,以 8/20μs 标准波形的电流作两次冲击的最大电流值,两次冲击时间间隔为 5 分钟,此时压敏电压变化率仍在±10%以内。 在一些资料上,会有通流容量这个概念,也可以把最大浪涌电流看作通流容量,通流容量比较难计算,多个压敏电阻并联,其压敏电压不变,通流量等于几者之和,要求并联的压敏电阻伏安特性尽量相同,否则易引起分流不均匀而损坏压敏电阻对选型来说,一般参照SPEC即可。 ▉ 静电电容 指的是压敏电阻器本身固有的电容容量,一般测试条件是振荡器频率为1KHz或1MHz,振荡器电压1Vrms。 ▉ 漏电流 现在一般SPEC不给出压敏电阻的漏电流参数,漏电流又称为等待电流,指压敏电阻器在规定的温度和最大直流电压下,流过压敏电阻器的电流。    选型要点    压敏电阻的选型,我总结了如下几点。 一、在交流回路中,V1mA(min)≥(2.2~2.5)*Vac,Vac是被保护交流电路工作电压有效值。 二、在直流回路中,V1mA(min)≥(1.6~2)*Vdc,Vdc是直流电路最大工作电压。 三、 如果被保护电路工作电压或耐压较低,而浪涌能量又比较大,则可选择压敏电压较低、片径较大的压敏电阻器。 四、如果工作电压或耐压较高,可选择压敏电压较高的压敏电阻器,既保护了电路,又能延长压敏电阻寿命。 五、压敏电阻的电容量一般是几十到几百pF,。 再来看看压敏电阻的分类。 按结构分:可以分为结型压敏电阻器、体型压敏电阻器、单颗粒层压敏电阻器和薄膜压敏电阻器。 按使用材料分:可分为氧化锌压敏电阻器、碳化硅压敏电阻器、金属氧化物压敏电阻器、锗(硅)压敏电阻器、钛酸钡压敏电阻器。 按伏安特性分:可分为对称型压敏电阻器(无极性)和非对称型压敏电阻器(有极性),我们一般使用的压敏电阻都是没有极性的。 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3平台登录_究竟什么是内核?我该如何高效学习?

01 前言 本文主要讲解什么是Linux内核,以及通过多张图片展示Linux内核的作用与功能,以便于读者能快速理解什么是Linux内核,能看懂Linux内核。 拥有超过1300万行的代码,Linux内核是世界上最大的开源项目之一,但是内核是什么,它用于什么? 02 什么是内核 内核是与计算机硬件接口的易替换软件的最低级别。它负责将所有以“用户模式”运行的应用程序连接到物理硬件,并允许称为服务器的进程使用进程间通信(IPC)彼此获取信息。 03 内核还要分种类? 是的,没错。 3.1 微内核 微内核只管理它必须管理的东西:CPU、内存和IPC。计算机中几乎所有的东西都可以被看作是一个附件,并且可以在用户模式下处理。微内核具有可移植性的优势,因为只要操作系统仍然试图以相同的方式访问硬件,就不必担心您是否更改了视频卡,甚至是操作系统。微内核对内存和安装空间的占用也非常小,而且它们往往更安全,因为只有特定的进程在用户模式下运行,而用户模式不具有管理员模式的高权限。 3.1.1 Pros 可移植性 安装占用空间小 小内存占用 安全 3.1.2 Cons 通过驱动程序,硬件更加抽象 硬件可能反应较慢,因为驱动程序处于用户模式 进程必须在队列中等待才能获得信息 进程不能在不等待的情况下访问其他进程 3.2 单内核 单内核与微内核相反,因为它们不仅包含CPU、内存和IPC,而且还包含设备驱动程序、文件系统管理和系统服务器调用等内容。单内核更擅长于访问硬件和多任务处理,因为如果一个程序需要从内存或运行中的其他进程中获取信息,那么它就有一条更直接的线路来访问信息,而不需要在队列中等待来完成任务。但是,这可能会导致问题,因为在管理模式下运行的东西越多,如果行为不正常,就会有越多的东西导致系统崩溃。 3.2.1 Pros 更直接地访问程序的硬件 流程之间更容易通信 如果支持您的设备,它应该不需要额外安装就可以工作 进程反应更快,因为没有等待处理器时间的队列 3.2.2 Cons 较大安装体积 较大内存占用 不太安全,因为所有操作都在管理模式下运行 04 混合的内核 混合内核能够选择在用户模式下运行什么,以及在管理模式下运行什么。通常情况下,设备驱动程序和文件系统I/O将在用户模式下运行,而IPC和服务器调用将保持在管理器模式下。这是两全其美,但通常需要硬件制造商做更多的工作,因为所有驱动程序的责任都由他们来承担。它还可能存在一些与微内核固有的延迟问题。 4.1 Pros 开发人员可以选择什么在用户模式下运行,什么在管理模式下运行 比单片内核更小的安装占用空间 比其他型号更灵活 4.2 Cons 会遭受与微内核相同的进程延迟 设备驱动程序需要由用户管理(通常) 05 Linux内核文件在哪里 Ubuntu中的内核文件存储在/boot文件夹中,称为vmlinux -version。vmlinuz这个名字来自于unix世界,早在60年代,他们就把内核简单地称为“unix”,所以当内核在90年代首次开发时,Linux就开始把内核称为“Linux”。 当开发虚拟内存以便更容易地进行多任务处理时,将“vm”放在文件的前面,以显示内核支持虚拟内存。有一段时间,Linux内核被称为vmlinux,但是内核变得太大,无法装入可用的引导内存,因此压缩了内核映像,并将末尾的x更改为z,以显示它是用zlib压缩的。并不总是使用相同的压缩,通常用LZMA或BZIP2替换,一些内核简单地称为zImage。 版本号将采用A.B.C.格式D在。B可能是2.6,C是您的版本,D表示您的补丁或补丁。 在/boot文件夹中还有其他非常重要的文件,称为initrd.img-version、system.map-version, config-version。initrd文件用作一个小RAM磁盘,用于提取和执行实际的内核文件。这个系统。map文件用于内核完全加载之前的内存管理,配置文件告诉内核在编译内核映像时要加载哪些选项和模块。 06 Linux内核体系结构 因为Linux内核是单片的,所以它比其他类型的内核占用空间最大,复杂度也最高。这是一个设计特性,在Linux早期引起了相当多的争论,并且仍然带有一些与单内核固有的相同的设计缺陷。 为了解决这些缺陷,Linux内核开发人员所做的一件事就是使内核模块可以在运行时加载和卸载,这意味着您可以动态地添加或删除内核的特性。这不仅可以向内核添加硬件功能,还可以包括运行服务器进程的模块,比如低级别虚拟化,但也可以替换整个内核,而不需要在某些情况下重启计算机。 想象一下,如果您可以升级到Windows服务包,而不需要重新启动…… 07 内核模块 如果Windows已经安装了所有可用的驱动程序,而您只需要打开所需的驱动程序怎么办?这本质上就是内核模块为Linux所做的。内核模块,也称为可加载内核模块(LKM),对于保持内核在不消耗所有可用内存的情况下与所有硬件一起工作是必不可少的。 模块通常向基本内核添加设备、文件系统和系统调用等功能。lkm的文件扩展名是.ko,通常存储在/lib/modules目录中。由于模块的特性,您可以通过在启动时使用menuconfig命令将模块设置为load或not load,或者通过编辑/boot/config文件,或者使用modprobe命令动态地加载和卸载模块,轻松定制内核。 第三方和封闭源码模块在一些发行版中是可用的,比如Ubuntu,默认情况下可能无法安装,因为这些模块的源代码是不可用的。该软件的开发人员(即nVidia、ATI等)不提供源代码,而是构建自己的模块并编译所需的.ko文件以便分发。虽然这些模块像beer一样是免费的,但它们不像speech那样是免费的,因此不包括在一些发行版中,因为维护人员认为它通过提供非免费软件“污染”了内核。 内核并不神奇,但对于任何正常运行的计算机来说,它都是必不可少的。Linux内核不同于OS X和Windows,因为它包含内核级别的驱动程序,并使许多东西“开箱即用”。希望您能对软件和硬件如何协同工作以及启动计算机所需的文件有更多的了解。 08 Linux 内核学习经验总结 开篇 学习内核,每个人都有自己的学习方法,仁者见仁智者见智。以下是我在学习过程中总结出来的东西,对自身来说,我认为比较有效率,拿出来跟大家交流一下。 内核学习,一偏之见;疏漏难免,恳请指正。 为什么写这篇博客 刚开始学内核的时候,不要执着于一个方面,不要专注于一个子系统就一头扎到实际的代码行中去,因为这样的话,牵涉的面会很广,会碰到很多困难,容易产生挫败感,一个函数体中(假设刚开始的时候正在学习某个方面的某个具体的功能函数)很可能掺杂着其他各个子系统方面设计理念(多是大量相关的数据结构或者全局变量,用于支撑该子系统的管理工作)下相应的代码实现,这个时候看到这些东西,纷繁芜杂,是没有头绪而且很不理解的,会产生很多很多的疑问,(这个时候如果对这些疑问纠缠不清,刨根问底,那么事实上就是在学习当前子系统的过程中频繁的去涉足其他子系统,这时候注意力就分散了),而事实上等了解了各个子系统后再回头看这些东西的话,就简单多了,而且思路也会比较清晰。所以,要避免 “只见树木,不见森林”,不要急于深入到底层代码中去,不要过早研究底层代码。 我在大二的时候刚开始接触内核,就犯了这个错误,一头扎到内存管理里头,去看非常底层的实现代码,虽然也是建立在内存管理的设计思想的基础上,但是相对来说,比较孤立,因为此时并没有学习其它子系统,应该说无论是视野还是思想,都比较狭隘,所以代码中牵涉到的其它子系统的实现我都直接跳过了,这一点还算聪明,当然也是迫不得已的。 我的学习方法 刚开始,我认为主要的问题在于你知道不知道,而不是理解不理解,某个子系统的实现采用了某种策略、方法,而你在学习中需要做的就是知道有这么一回事儿,然后才是理解所描述的策略或者方法。 根据自己的学习经验,刚开始学习内核的时候,我认为要做的是在自己的脑海中建立起内核的大体框架,理解各个子系统的设计理念和构建思想,这些理念和思想会从宏观上呈献给你清晰的脉络,就像一个去除了枝枝叶叶的大树的主干,一目了然;当然,肯定还会涉及到具体的实现方法、函数,但是此时接触到的函数或者方法位于内核实现的较高的层次,是主(要)函数,已经了解到这些函数,针对的是哪些设计思想,实现了什么样的功能,达成了什么样的目的,混个脸熟的说法在这儿也是成立的。至于该主函数所调用的其它的辅助性函数就等同于枝枝叶叶了,不必太早就去深究。此时,也就初步建立起了内核子系统框架和代码实现之间的关联,关联其实很简单,比如一看到某个函数名字,就想起这个函数是针对哪个子系统的,实现了什么功能。 我认为此时要看的就是LKD3,这本书算是泛泛而谈,主要就是从概念,设计,大的实现方法上描述各个子系统,而对于具体的相关的函数实现的代码讲解很少涉及(对比于ULK3,此书主要就是关于具体函数代码的具体实现的深入分析,当然,你也可以看,但是过早看这本书,会感觉很痛苦,很枯燥无味,基本上都是函数的实现),很少,但不是没有,这就很好,满足我们当前的需求,还避免我们过早深入到实际的代码中去。而且本书在一些重要的点上还给出了写程序时的注意事项,算是指导性建议。主要的子系统包括:内存管理,进程管理和调度,系统调用,中断和异常,内核同步,时间和定时器管理,虚拟文件系统,块I/O层,设备和模块。(这里的先后顺序其实就是LKD3的目录的顺序)。 我学习的时候是三本书交叉着看的,先看LKD3,专于一个子系统,主要就是了解设计的原理和思想,当然也会碰到对一些主要函数的介绍,但大多就是该函数基于前面介绍的思想和原理完成了什么样的功能,该书并没有就函数本身的实现进行深入剖析。然后再看ULK3和PLKA上看同样的子系统,但是并不仔细分析底层具体函数的代码,只是粗略地、不求甚解地看,甚至不看。因为,有些时候,在其中一本书的某个点上,卡壳了,不是很理解了,在另外的书上你可能就碰到对同一个问题的不同角度的描述,说不准哪句话就能让你豁然开朗,如醍醐灌顶。我经常碰到这种情况。 并不是说学习过程中对一些函数体的实现完全就忽略掉,只要自己想彻底了解其代码实现,没有谁会阻止你。我是在反复阅读过程中慢慢深入的。比如VFS中文件打开需要对路径进行分析,需要考虑的细节不少(.././之类的),但是其代码实现是很好理解的。再比如,CFS调度中根据shedule latency、队列中进程个数及其nice值(使用的是动态优先级)计算出分配给进程的时间片,没理由不看的,这个太重要了,而且也很有意思。 ULK3也会有设计原理与思想之类的概括性介绍,基本上都位于某个主题的开篇段落。但是更多的是对支持该原理和思想的主要函数实现的具体分析,同样在首段,一句话综述函数的功能,然后对函数的实现以1、2、3,或者a、b、c步骤的形式进行讲解。我只是有选择性的看,有时候对照着用source insight打开的源码,确认一下代码大体上确实是按书中所描述的步骤实现的,就当是增加感性认识。由于步骤中掺杂着各种针对不同实现目的安全性、有效性检查,如果不理解就先跳过。这并不妨碍你对函数体功能实现的整体把握。 PLKA介于LKD3和ULK3之间。我觉得PLKA的作者(看照片,真一德国帅小伙,技术如此了得)肯定看过ULK,无论他的本意还是有意,总之PLKA还是跟ULK有所不同,对函数的仔细讲解都做补充说明,去掉函数体中边边角角的情况,比如一些特殊情况的处理,有效性检查等,而不妨碍对整个函数体功能的理解,这些他都有所交代,做了声明;而且,就像LKD3一样,在某些点上也给出了指导性编程建议。作者们甚至对同一个主要函数的讲解的着重点都不一样。这样的话,对我们学习的人而言,有助于加深理解。另外,我认为很重要的一点就是PLKA针对的2.6.24的内核版本,而ULK是2.6.11,LKD3是2.6.34。在某些方面PLKA比较接近现代的实现。其实作者们之所以分别选择11或者24,都是因为在版本发行树中,这两个版本在某些方面都做了不小的变动,或者说是具有标志性的转折点(这些信息大多是在书中的引言部分介绍的,具体的细节我想不起来了)。 Intel V3,针对X86的CPU,本书自然是系统编程的权威。内核部分实现都可以在本书找到其根源。所以,在读以上三本书某个子系统的时候,不要忘记可以在V3中相应章节找到一些基础性支撑信息。 在读书过程中,会产生相当多的疑问,这一点是确信无疑的。大到搞不明白一个设计思想,小到不理解某行代码的用途。各个方面,各种疑问,你完全可以把不理解的地方都记录下来(不过,我并没有这么做,没有把疑问全部记下来,只标记了很少一部分我认为很关键的几个问题),专门写到一张纸上,不对,一个本上,我确信会产生这么多的疑问,不然内核相关的论坛早就可以关闭了。其实,大部分的问题(其中很多问题都是你知道不知道有这么一回事的问题)都可以迎刃而解,只要你肯回头再看,书读百遍,其义自现。多看几遍,前前后后的联系明白个七七八八是没有问题的。我也这么做了,针对某些子系统也看了好几遍,切身体会。 当你按顺序学习这些子系统的时候,前面的章节很可能会引用后面的章节,就像PLKA的作者说的那样,完全没有向后引用是不可能的,他能做的只是尽量减少这种引用而又不损害你对当前问题的理解。不理解,没关系,跳过就行了。后面的章节同样会有向前章节的引用,不过这个问题就简单一些了  ,你可以再回头去看相应的介绍,当时你不太理解的东西,很可能这个时候就知道了它的设计的目的以及具体的应用。不求甚解只是暂时的。比如说,内核各个子系统之间的交互和引用在代码中的体现就是实现函数穿插调用,比如你在内存管理章节学习了的内存分配和释放的函数,而你是了解内存在先的,在学习驱动或者模块的时候就会碰到这些函数的调用,这样也就比较容易接受,不至于太过茫然;再比如,你了解了系统时间和定时器的管理,再回头看中断和异常中bottom half的调度实现,你对它的理解就会加深一层。 子系统进行管理工作需要大量的数据结构。子系统之间交互的一种方式就是各个子系统各自的主要数据结构通过指针成员相互引用。学习过程中,参考书上在讲解某个子系统的时候会对数据结构中主要成员的用途解释一下,但肯定不会覆盖全部(成员比较多的情况,例如task_struct),对其它子系统基于某个功能实现的引用可能解释了,也可能没做解释,还可能说这个变量在何处会做进一步说明。所以,不要纠结于一个不理解的点上,暂且放过,回头还可以看的。之间的联系可以在对各个子系统都有所了解之后再建立起来。其实,我仍然在强调先理解概念和框架的重要性。 等我们完成了建立框架这一步,就可以选择一个比较感兴趣的子系统,比如驱动、网络,或者文件系统之类的。这个时候你再去深入了解底层代码实现,相较于一开始就钻研代码,更容易一些,而且碰到了不解之处,或者忘记了某个方面的实现,此时你完全可以找到相应的子系统,因为你知道在哪去找,查漏补缺,不仅完成了对当前函数的钻研,而且可以回顾、温习以前的内容,融会贯通的时机就在这里了。 《深入理解linux虚拟内存》(2.4内核版本),LDD3,《深入理解linux网络技术内幕》,几乎每一个子系统都需要一本书的容量去讲解,所以说,刚开始学习不宜对某个模块太过深入,等对各个子系统都有所了解了,再有针对性的去学习一个特定的子系统。这时候对其它系统的援引都可以让我们不再感到茫然、复杂,不知所云。 比如,LDD3中的以下所列章节:构造和运行模块,并发和竞态,时间、延迟及延缓操作,分配内存,中断处理等,都属于驱动开发的支撑性子系统,虽说本书对这些子系统都专门开辟一个章节进行讲解,但是详细程度怎么能比得上PLKA,ULK3,LKD3这三本书,看完这三本书,你会发现读LDD3这些章节的时候简直跟喝白开水一样,太随意了,因为LDD3的讲解比之LKD3更粗略。打好了基础,PCI、USB、TTY驱动,块设备驱动,网卡驱动,需要了解和学习的东西就比较有针对性了。这些子系统就属于通用子系统,了解之后,基于这些子系统的子系统的开发—驱动(需进一步针对硬件特性)和网络(需进一步理解各种协议)—相对而言,其学习难度大大降低,学习进度大大加快,学习效率大大提升。说着容易做来难。达到这样一种效果的前提就是:必须得静下心来,认真读书,要看得进去,PLKA,ULK3厚得都跟砖头块儿一样,令人望之生畏,如果没有兴趣,没有热情,没有毅力,无论如何都是不行,因为需要时间,需要很长时间。我并不是说必须打好了基础才可以进行驱动开发,只是说打好了基础的情况下进行开发会更轻松,更有效率,而且自己对内核代码的驾驭能力会更强大。这只是我个人见解,我自己的学习方式,仅供参考。 语言 PLKA是个德国人用德语写的,后来翻译成英文,又从英文翻译成中文,我在网上书店里没有找到它的纸质英文版,所以就买了中文版的。ULK3和LKD3都是英文版的。大牛们写的书,遣词造句真的是简洁,易懂,看原版对我们学习计算机编程的程序员来说完全不成问题,最好原汁原味。如果一本书确实翻译地很好,我们当然可以看中文版的,用母语进行学习,理解速度和学习进度当然是很快的,不作他想。看英文的时候不要脑子里想着把他翻译成中文,没必要。 API感想 “比起知道你所用技术的重要性,成为某一个特别领域的专家是不重要的。知道某一个具体API调用一点好处都没有,当你需要他的时候只要查询下就好了。”这句话源于我看到的一篇翻译过来的博客。我想强调的就是,这句话针应用型编程再合适不过,但是内核API就不完全如此。 内核相当复杂,学习起来很不容易,但是当你学习到一定程度,你会发现,如果自己打算写内核代码,到最后要关注的仍然是API接口,只不过这些API绝大部分是跨平台的,满足可移植性。内核黑客基本上已经标准化、文档化了这些接口,你所要做的只是调用而已。当然,在使用的时候,最好对可移植性这一话题在内核中的编码约定烂熟于心,这样才会写出可移植性的代码。就像应用程序一样,可以使用开发商提供的动态库API,或者使用开源API。同样是调用API,不同点在于使用内核API要比使用应用API了解的东西要多出许多。 当你了解了操作系统的实现—这些实现可都是对应用程序的基础性支撑啊—你再去写应用程序的时候,应用程序中用到的多线程,定时器,同步锁机制等等等等,使用共享库API的时候,联系到操作系统,从而把对该API的文档描述同自己所了解到的这些方面在内核中的相应支撑性实现结合起来进行考虑,这会指导你选择使用哪一个API接口,选出效率最高的实现方式。对系统编程颇有了解的话,对应用编程不无益处,甚至可以说是大有好处。 设计实现的本质,知道还是理解 操作系统是介于底层硬件和应用软件之间的接口,其各个子系统的实现很大程度上依赖于硬件特性。书上介绍这些子系统的设计和实现的时候,我们读过了,也就知道了,如果再深入考虑一下,为什么整体架构要按照这种方式组织,为什么局部函数要遵循这样的步骤处理,知其然,知其所以然,如果你知道了某个功能的实现是因为芯片就是这么设计的,CPU就是这么做的,那么你的疑问也就基本上到此为止了。再深究,就是芯片架构方面的设计与实现,对于程序员来讲,无论是系统还是应用程序员,足迹探究到这里,已经解决了很多疑问,因为我们的工作性质偏软,而这些东西实在是够硬。 比如,ULK3中讲解的中断和异常的实现,究其根源,那是因为Intel x86系列就是这么设计的,去看看Intel V3手册中相应章节介绍,都可以为ULK3中描述的代码实现方式找到注解。还有时间和定时器管理,同样可以在Intel V3  对APIC的介绍中获取足够的信息,操作系统就是依据这些硬件特性来实现软件方法定义的。 又是那句话,不是理解不理解的问题,而是知道不知道的问题。有时候,知道了,就理解了。在整个学习过程中,知道,理解,知道,理解,知道……,交叉反复。为什么开始和结尾都是知道,而理解只是中间步骤呢?世界上万事万物自有其规律,人类只是发现而已,实践是第一位的,实践就是知道的过程,实践产生经验,经验的总结就是理论,理论源于实践,理论才需要理解。我们学习内核,深入研究,搞来搞去,又回到了芯片上,芯片是物质的,芯片的功用基于自然界中物质本有的物理和电子特性。追本溯源,此之谓也。 动手写代码 纸上得来终觉浅,绝知此事要躬行。只看书是绝对不行的,一定要结合课本给出的编程建议自己敲代码。刚开始就以模块形式测试好了,或者自己编译一个开发版本的内核。一台机器的话,使用UML方式调试,内核控制路走到哪一步,单步调试看看程序执行过程,比书上的讲解更直观明了。一定要动手实际操作。 参考书 LDD3 …

摩登3测速登录地址_电机开发套件首重高能效

推动高能效创新的安森美半导体(ON Semiconductor,美国纳斯达克上市代号:ON),推出,以加速开发更高能效的电机控制方案,适用于从低于1 kW到超过10 kW的应用。 电机占工业化国家产生和消耗的全部电力的一半以上。这些电机大多数是交流 (AC) 感应电机,平均能效仅44%。为了提高能效,电机驱动设计人员必须了解这些和其他类型的电机在所有负载条件下如何工作,并针对可变条件进行智能补偿。电机开发套件解决了提高能源利用率的迫切需求。 电机开发套件(MDK)由越来越多的电源板之一组成,连接到一个通用控制器板(UCB)。这些电源板采用安森美半导体各种不同的电机驱动变频方案,从高压集成模块到低压分立MOSFET。UCB是个通用控制平台,可与任何电源板连接,使工程师能够评估可替代各种类型的电机以及各种功率水平下的电机控制技术。 智能电机控制需要灵活且可编程的方法。UCB基于赛灵思(Xilinx)公司的Zynq®-7000系统单芯片(SoC)系列。该功能强大的器件集成两个ARM®Cortex™-A9处理器内核和一个现场可编程门阵列(FPGA)架构,从而提供软硬件配置的最佳组合。该开发板还提供一个10通道差分模数转换器(ADC)、12条脉宽调制(PWM)通道和许多可配置的数字外设。通信端口包括USB、JTAG和UART,以及千兆以太网PHY。 高效的电机控制是安森美半导体的业务焦点之一。公司应用其丰富的经验和广泛的分立器件、智能功率模块(IPM)和压铸模功率集成模块(TM PIM)阵容来提高能效。MDK汇集了其专知和技术,帮助工程师快速开发更高能效的方案,用于使用电机的任何应用。 安森美半导体的MDK为评估可变速电机变频器方案提供“开箱即用”的体验。为实现这,模块化生态系统包括UCB和若干电源评估板,采用安森美半导体同类最佳的功率器件开发。软件开发支持来自Xilinx以Vivado®设计套件的形式进行高层次综合。USB也可通过Xilinx的开源项目PYNQ使用Python进行编程。 说:“安森美半导体已提供广泛的电源方案阵容,针对可变电机控制进行了优化。电机开发套件将这些技术整合到一个单一的生态系统中,可以真正帮助设计团队加速开发更高能效的电机控制方案的进程。” 说:“优化电机的能效对地球上工厂和工业设备的碳足迹有巨大影响。安森美半导体的技术结合赛灵思Zynq SoC的高性能电机控制,大幅降低运营成本,为用户的定制化提供最强的适应性,并对环境做出积极贡献。安森美半导体的新电机开发套件使这一切变得触手可及,并促进了从原型到生产的迁移。” MDK当前支持两个电机电源板。SECO-1KW-MCTRL-GEVB适用于驱动最高1 kW的电动机,SECO-MDK-4KW-65SMP31-GEVB适用于驱动最高4 kW的电动机。这两款电源板均使用安森美半导体的IPM技术,将于2020年第4季度上市。另外一款基于安森美半导体TMPIM技术的电源板还将在2021年第1季度推出,用于驱动高达10 kW的电机。预计MDK生态系统将期望进一步增添更多的电源板和扩展设计支援。 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3主管554258:_硅光电倍增管 (SiPM) 直接飞行时间 (dToF) 激光雷达平台为工业测距应用提供现成的设计

推动高能效创新的安森美半导体 (ON Semiconductor,美国纳斯达克上市代号:ON),推出了由该公司。 光检测和测距或激光雷达的应用在所有领域都在增长,包括机器人和强制要求毫米范围精度的工业接近感知。它通常基于dToF方法,测量通常在近红外 (NIR) 波长范围内的一个光脉冲往返于一个物体所需的时间。 尽管原理很简单,但其应用可能会带来挑战性,例如周围太阳光较强等环境因素。为了准确确定范围,接收器需要捕获尽可能多的信号。就响应时间和灵敏度而言,传统的光电二极管在这方面会受到影响。安森美半导体开发的硅光电倍增管 (SiPM) 传感器提供更快的响应时间和高检测效率,克服了这些不足。该参考平台使用安森美半导体第二代SiPM 传感器RB系列,在红色和NIR范围都带来更高的性能。 安森美半导体开发的SiPM dToF激光雷达平台提供低成本、单点激光雷达的完整方案,原始设备制造商 (OEM) 可灵活调整并投入生产,以创建工业测距应用。它包括NIR激光二极管、SiPM传感器和光学器件,以及将检测到的信号转换为经过时间,以及将经过时间转换为距离所需的数字处理。 为加快客户的上市时间,安森美半导体提供该参考平台的所有设计数据,涵盖原理图、物料单 (BoM) 、gerber文件和PCB设计文件。客户还可以访问基于PC的图形用户接口(GUI),提供随时间变化的测量结果的图形。生成的直方图进一步证明该系统在测距、碰撞检测和3D制图等应用的能力。 说:“使用dToF激光雷达进行测距,满足了许多应用的关键需求,从自主导航到地图绘制到监控。但是,开发基于dToF激光雷达的系统可能具有挑战性。我司的这个平台显然证实这领先技术的效用。有了经验证的设计,客户就能更快地进行概念验证,并迅速将产品推向市场。” SiPM dToF激光雷达平台可检测10厘米至23米距离的物体。使用提供的GUI提供开箱即用的体验,使工程师可以立即开始评估该技术。该设计已获得美国食品和药物管理局 (FDA) 一类认证,并符合IEC / EN 60825-1:2014和21 CFR 1040.10 / 1040.11激光安全标准。 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3内部554258_嵌入式四大通信接口的神解释

1、 裘千丈轻功水上漂之UART 射雕英雄传中的裘千丈说,UART就是我的轻功水上漂过河。想从河上过(通信),提前布暗桩,行走时步伐按桩距固定(波特率提前确定),步幅太大或太小都会落水。为了不被二弟裘千仞识破,可以安排侍卫在对岸监视通知,没风险才开始表演(流控)。为了保证踩点准确,隔一段距离定个特殊标记的粗木桩。 UART 通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通信双方接三根线,RX、TX和GND,TX用于发送数据,RX用于接受数据,双方收发交叉对接,支持全双工方式。 因为没有时钟控制,什么时机开始发数据,且保证对方正确接收? 如A发数据到B,平时空闲时A.TX 和 B.RX.保持1,当A.TX先发0作为起始位,告诉B请注意,我要发数据了。然后就开始发数据,数据位可配置,通常是5位,6位,7位,8位,一帧数据发完后,A.TX给个高电平告诉B.RX我发完了一帧。如果开启校验位,在发停止位之前发送个校验位,一般都不需要校验位了,短距离有线传输出错的概率非常小。如果还有数据,则重复前面的操作。 一般软件配置串口,有波特率,数据位、停止位、校验位、流控。分别表示传输速度,一帧数据的长度,以及发完告知停止,发完是否校验,是否进行发送控制。看起来参数很多,针对个人经验,一般都是固定8位数据位,1位停止位、无校验、无流控,只是配置波特率。 UART没有时钟控制数据捕获时机,依靠通信前就定义波特率,双方按定义的频率读写数据位,正如裘千丈的水上漂,一旦暗桩安装固定,就得按固定的步长行走,否则就会出错落水。 UART在水上漂项目可以,但是传输效率有限,一般高到921600,如果再高可能出现误码,继续加高,就是高空飞行,最后裘千丈就是期望在高空也行走自如,想攀上黄蓉乘坐的大雕逃命,不慎坠落,死于飞行事故。 2、叫你一声你敢答应吗之I2C 作为太上老君看银炉的童子,银角大王最懂I2C,万千人中我叫你一声,你答应了就倒霉(从机地址正确才能通信)。 IIC(Inter Integrated Circuit)两根线,一条时钟线SCL和一条数据线SDA,所以是半双工通信,主从模式,支持一对多,一个银角大王可以对付一群猴子,每个猴子名字不同(从设备的I2C地址不同),点名叫到谁,谁就被紫金葫芦带走。 假设主机A给从机B发数据(A.SCL接B.SCL,A.SDA接B.SDA),根据应用,A可以同时接B,C,D。空闲时SDA和SCL上的电平都为高电平。 起始和停止起始条件S:当SCL高电平时,SDA由高电平向低电平转换;停止条件P:当SCL高电平时,SDA由低电平向高电平转换。起始和停止条件一般由主机产生,总线在起始条件后处于busy的状态,在停止条件的某段时间后,总线才再次处于空闲状态。 空闲时SDA和SCL上的电平都为高电平。A先把SDA拉低,等SDA变为低电平后再把SCL拉低(以上两个动作构成了I2C的起始位),此时SDA就可以发送数据了,与此同时,SCL发送一定周期的脉冲,SDA发送数据和SCL发送脉冲的要符合的关系是:SDA必须在SCL是高电平时保持有效,在SCL是低电平时发送下一位(SCL会在上升沿对SDA进行采样)。 传输与响应一次传8位数据,8位数据传输结束后A释放SDA,SCL再发一个脉冲(这是第九个脉冲),触发B将SDA置为低电平表示确认(该低电平称为ACK)。最后SCL先变为高电平,SDA再变为高电平(以上两个动作称为结束标志),如果B没有将SDA置为0 ,则A停止发送下一帧数据.。 I2C总线上的每个设备都有唯一地址,数据包传输时先发送地址位,接着才是数据。一个地址字节由7个地址位(可以挂128个设备)和1个指示位组成(7位寻址模式),0表示写,1表示读。一般芯片手册I2C地址都是7位地址,有些与某个引脚的电平相关,主机控制最后读写位。 实际项目一般都是采用I2C库,有的库要求传入的是8位的写的地址,有的是7位,由接口函数再区分读写补位。当然,最愚蠢的办法是从0到255定时循环读某个寄存器地址,读到正确值时的地址就是正确的从机地址。 一般情况下使用I2C库,除了配置从机地址,其他的起始、结束等时序等其实不太关注,只需要配置时钟频率,一般看从机最大支持多少,以及主机的系统时钟,太高会偶尔出现错误,再没有时间要求的情况下,时钟越低越稳定。 3、慕容复斗转星移之SPI 天龙八部的慕容复:虽然我不如乔峰可以使出降龙十八掌,但是他对我出手,我也以彼之道还施彼身,对方输出时也会被反噬,互相伤害,他停止时钟我也无可奈何。正如SPI,主机开启了时钟发数据,从机也在同时输出,时钟停,大家都收手。 SPI 串行外设接口(Serial Peripheral Interface)主从模式,一种高速的,全双工同步的通信总线。标准SPI是4条线。SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选,有些也称为SS)。 SDO/MOSI – 主设备数据输出,从设备数据输入 ,master output slave input;SDI/MISO – 主设备数据输入,从设备数据输出,master input slave output;SCLK – 时钟信号,由主设备产生;CS/SS – 从设备使能信号,由主设备控制。当有多个从设备的时候,主设备通过片选引脚选择其中一个从设备进行通信。(I2C是通过软件协议实现多选一,SPI是通过硬件实现)。 当主机控制CS,开启时钟闸门,主从双方就可以开始放数据位或者取数据位进行交互了,但是在什么时机开始,就有标准了。根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置。   CPOL:时钟极性选择,为0时SPI总线空闲为低电平,为1时SPI总线空闲为高电平    CPHA:时钟相位选择,为0时在SCK第一个跳变沿采样,为1时在SCK第二个跳变沿采样 mode CPOL CPHA 0 0 0 1 0 1 2 1 0 3 1 1 这样就有四种模式。以模式1为例,空闲时为低,第一次时钟跳变采样,也就是上升沿读数采样,对着下降沿放数据。如果实在分不清,还有愚蠢的办法,四种模式全部尝试一次,就可知道正确模式。 SPI传输数据没有位数限制,只要定义收发高位在前还是低位在前,可以持续高速传输。 正如前面,若是乔峰收手,慕容复就没法使出降龙十八掌的效果,但是他可以当面骂乔峰是契丹狗,乔峰一怒之下就发功,慕容复就奸计得逞。这契丹狗三字翻译为软件术语就是触发中断,从机发中断告知主机我有事来找我;主机定时查询也可实现,只是使用情况更少。 4、裘千尺的吐枣核绝技与1-wire 裘千丈的三妹裘千尺被囚地下,她以口喷射枣核钉打在枣树,树的摇晃就会掉下枣子充饥。这枣核钉是单向操作,用力过猛,枣核透过枣树,用力太轻或者射偏了,枣树没有反应,这样枣核用完了就悲剧了。可见这绝技,看起来简便,实则背后隐藏了精确控制,对时机、位置控制要完美,如1-wire通信,单线控制,时钟精准。 1-wire总线接口简单,一根线就可以,一般内部开漏输出,外部硬件上拉。 1-wire使用一条线来传送的四种信令组成,包括复位脉冲和在线应答脉冲的复位序列、写 0 时隙、写 1 时隙、读时隙。除在线应答脉冲以外,所有其它信号都由总线主机发出,并且发送的所有数据和命令都是字节的低位在前。主机与从机的数据通信是通过时隙完成的,在每个时隙只能传送一位数据。通过写时隙可把数据从主机传送给从机,通过读时隙可把数据由从器件传送给主机,将完成一位传输的时间称为一个时隙。 一般操作流程参考外设芯片手册,主要是不同平台的延时处理,需要软件实现1us延时的接口,否则数据通信异常。 5、秘籍功法 四种接口,每个都有合适的应用场景,对硬件端口的占用、对软件的控制要求、通信效率也不相同。尤其前3种属于常用协议,一般都支持硬件接口,厂家也一般提供hal库,对软件开发人员的要求逐渐降低。这也导致代码应用很溜,实际底层原理略微欠缺,一旦通信异常或者有特殊需求就无从下手。如使用GPIO模拟出UART,使用SPI实现AT功能。 武林人士一般都追求失传的武林秘籍,正如软件开发人员,有问题总是寄希望与其他人的经验总结,或者厂家的技术支持或源码,而不是创造新的功法。笑傲江湖的岳不群本是华山派掌门,精通紫霞神功,武功属于一流,但是没继续专研自家内功,为了辟邪剑谱自宫了,软件开发人员想重蹈覆辙么? 不论剑宗、气宗,先把功能跑通再反推代码原理和实现流程,还是先理清时序和原理再编码实现功能,短期内剑宗效率高,加工资快;气宗则可能被淘汰,尤其在势利的小公司,不注重新人培养。如果合二为一,项目紧急则拿来就用,空闲时专研总结,取长补短,则是完美开发人员的素质。 软件开发没有秘笈功法,全靠个人学习总结。 猜你喜欢 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3测试路线_GitHub源代码泄露,CEO回应:这是个意外

作者 | 褚 杏娟 疯狂封禁项目后,开发者的一次抗议?   今天, TypeScript 开发者 Resynth 发文称,代码托管服务 GitHub 的全部源代码被泄露。他表示,在向官方 GitHub DMCA 提交的可疑文件中,一个身份不明的人利用 GitHub 应用程序中的一个漏洞冒充 GitHub CEO Nat Friedman 上传了机密源代码。 疑似泄露代码地址: https://web.archive.org/web/20201104050026if_/https://github.com/github/dmca/tree/565ece486c7c1652754d7b6d2b5ed9cb4097f9d5 随后,Nat Friedman 迅速在 Hackernews 的帖子上做了回复。他表示 GitHub 没有被黑客入侵,一切都很正常。所谓泄露的代码是几个月前他们意外地将 GitHub Enterprise Server 源代码未脱敏 / 混淆的 tarball 交付给了一些客户。 1 随意封禁,GitHub 被指没有开源精神   有开发者指出,此次泄露事件与 GitHub 上周下架 youtube-dl 和后续一系列动作有关,开发者用这种方式来进行抗争。 上周五,在应美国唱片业协会(RIAA)的要求下, GitHub 下架了平台上最受欢迎的项目之一:下载器项目 YouTube-dl  。但 RIAA 的禁令起到了相反的效果,很多开发人员开始对此表示抗议,并发布了更多代码副本。事件发生以前,在 GitHub 上搜索 Youtube-dl 相关的项目只有 20 多个,而现在至少能搜出 4100 多个。 其实对于 GitHub 来说,封禁项目不是什么新鲜事。 去年 5 月,GitHub 更新了用户协议,表明 GitHub 的产品和服务适用于美国出口管制法律。当年 7 月起,GitHub 基于美国出口管理条例,开始对伊朗、叙利亚和克里米亚的私人 repo 和付费账户实施限制。 从克里米亚地区的俄罗斯籍开发者到全部伊朗境内开发者再到定居芬兰的伊朗籍开发者,统统遭遇了账号被封无法创建私有库、已经创建的私有库被关闭等问题。而这些开发者并未得到 GitHub 提前通知,没有任何缓冲备份的时间。 今年 3 月份,GitHub 封禁了一个属于微软的前端开源项目 Aurelia,理由是项目中有两名来自伊朗的外部贡献者。Aurelia 是微软开发的 JavaScript 框架,已开源了 5 年。 这再次引发了开发者们的质疑:GitHub 封禁项目是否太随意?这难道不是与开源精神背道而驰? 事件不断发酵,GitHub CEO 不得不对此事进行道歉:关闭此帐户显然是一个可怕的错误。我们正在调查具体过程,并更改规则以确保此类问题不会再次发生。当然这一声明并没有阻止封禁事件的再次发生。 此事也引发了后续的一个讨论:GitHub 上的技术是各国志愿者撰写并无偿分享,并非美国购买有著作权的所有物,美国无权拿不属于自己的东西制裁别人甚至“拿伊朗的技术制裁伊朗”。GitHub 最后在争议下觉得有所理亏而改变作法,被封禁的用户可以下载回自己的作品,但依然不能在社区里查看代码。 但无数开发者已经深刻的意识到,被微软收购后的 GitHub 说到底还是一家美国企业。开源虽然无国界,但 GitHub 却是有国界的。有趣的是,GitHub 今年初发布的《八度宇宙状态》报告显示,截止 2019 年,GitHub 上共有 4000 万名开发者,而 80%的代码贡献者来自美国以外的地区。 2 GitHub 为什么不开源自己的代码? “GitHub 本身不是开源的,这使我永远不满意。”有开发者表示。 这次 GitHub 源代码疑似泄露事件,刺激了开发者对 GitHub 的讨论:既然源代码如此容易就可以获得,为什么 GitHub 不开源?…

摩登3平台首页_荣耀新机细节遭曝光,采用联发科天玑 800U 处理器,4色可选

在下述的内容中,小编将会对荣耀新机的最新消息予以报道,如果华为系列的智能手机是您想要了解的焦点之一,不妨和小编共同阅读这篇文章哦。 数码博主 @数码闲聊站 今日爆料称,荣耀即将发布新机,该机将采用 6.53 英寸 FHD + 分辨率 60Hz 刷新率的 OLED 水滴屏,前置 16MP 镜头,后置矩阵四摄模组,包括 64MP+8MP+2MP+2MP。 其他方面,该机采用联发科天玑 800U 处理器,支持 66W 快充,内置 3800mAh,厚约 7.46mm,重 179g,将提供幻夜黑、冰岛幻境、钛空银、蓝水翡翠四种配色。 而在配置方面,荣耀新机将会搭载基于7纳米工艺制程打造的天玑800U芯片。该款芯片采用了2个主频为2.4GHz的ARM Cortex-A76大核和6个2.0GHz主频的ARM Cortex-A55高能效核心,安兔兔跑分超过了30万,性能表现能够满足日常的使用和游戏。 影像方面,荣耀新机搭载了6400万+800万+200万+200万的后置四摄,前置则为1600万单摄。此外,荣耀新机还内置了一块3800mAh容量电池,用上了与华为Mate40系列同款的66W快充,在快充方面的体验值得期待。 以上便是小编此次带来的全部内容,十分感谢大家的耐心阅读,想要了解更多相关内容,或者更多精彩内容,请一定关注我们网站哦。

摩登3测速登录地址_够轻!罗技 GPW 新款 G Pro Superlight 鼠标遭曝光

本文中,小编将对罗技 GPW 新款 G Pro Superlight 鼠标予以介绍,如果你想对它的详细情况有所认识,或者想要增进对它的了解程度,不妨请看以下内容哦。 罗技新款G PRO Superlight鼠标宣传片近日在外网遭泄露,全面展示了这款鼠标的外观,和 GPW 几乎一样,不同的是新款对鼠标内外全面减重 25%。相比 GPW 80g 重量,新款重量小于 63g,这在目前一众轻量化设计的鼠标里,也属于相当轻的存在了。 外观方面,G PRO Superlight与GPW没有明显变化,基于GPW优化调整,保持了对称式鼠型,仅保留左侧按键,取消了右边侧键布局,尺寸仍然是125mm*63.5mm*40mm。 本次新款G PRO Superlight在重量上得到了进一步的优化,鼠标内外全面减重25%,相比GPW 80g的重量来说足足少了17g,仅为63g。 罗技 新款G PRO Superlight的更多信息,形状和尺寸保持不变,为 125 x 63.5 x 40mm,但该鼠标似乎依然是 micro USB 接口。 以上便是小编此次想要和大家共同分享的内容,如果你对本文内容感到满意,不妨持续关注我们网站哟。最后,十分感谢大家的阅读,have a nice day!

摩登3新闻554258:_芯片产能供不应求,台积电大规模下单光刻机

近半年来,芯片代工几乎进入行业旺季,许多芯片订单超过半年的排队期。芯片代工厂无法消耗如此之多芯片订单,导致产能无法赶上市场消耗,许多企业只能选择自己购买芯片制造设备。 而据TOMSHARDWARE报道,台积电表示其部署的极紫外光(EUV)光刻工具已占全球安装和运行总量的50%左右,这意味着其使用的EUV机器数量超过了业内其他任何一家公司。为了保持领先,台积电已经下单订购了至少13台ASML的Twinscan NXE EUV光刻机,将在2021年全年交付,不过具体的交付和安装时间表尚不清楚。同时,台积电明年的实际需求可能高达16 – 17台EUV光刻机。 在抢购EUV光刻机上,虽然台积电抢占先机,但是台积电也在为光刻机的事情发愁,甚至有报道声称碰过会将一部分M1芯片交给三星代工,主要还是因为台积电5nm产能不足,其实我们所讲述的产能不足,就是一个相对应的概念,要是市场上面的需求量不多的话,那么就不会出现这种供不应求的事情。 不仅仅是苹果、高通等科技巨头都需要用到这种先进的工艺技术,这里面已经不光包含了5nm工艺,就连7nm工艺也是需要用到EUV光刻机的,但是EUV光刻机的数量确实还有限,虽然我们现在说台积电斥巨资购买了55台光刻机,但是这么多台机器还不够满足市场所需吗? 台积电使用ASML的Twinscan NXE EUV光刻机在其N7+以及N5节点上制造芯片,但在未来几个季度,该公司将增加N6(实际上将在2020年第四季度或2021年第一季度进入HVM)以及同样具有EUV层的N5P工艺。台积电对EUV工具的需求正在增加是因为其技术越来越复杂,更多地方需要使用极紫外光刻工具处理。台积电的N7+使用EUV来处理最多4层,以减少制造高度复杂的电路时多图案技术的使用。 根据ASML的官方数据,2018年至2019年,每月产能约4.5万片晶圆(WSPM),一个EUV层需要一台Twinscan NXE光刻机。随着工具生产效率的提高,WSPM的数量也在增长。如果要为一个准备使用N3或更先进节点制造工艺的GigaFab(产能高于每月10万片)配备设备,台积电在该晶圆厂至少需要40台EUV光刻设备。 ASML最新推出的Twinscan NXE:3400B和NXE:3400C光刻系统价格相当昂贵。早在10月份,ASML就透露,其订单中的4套EUV系统价值5.95亿欧元(约合7.03亿美元),因此单台设备的成本可能高达1.4875亿欧元(1.7575亿美元)。也就是说,13套EUV设备可能要花费台积电高达22.84亿美元。 但在EUV工具方面,钱并不是唯一的考虑因素。ASML是唯一生产和安装EUV光刻机的公司,它的生产和安装能力相对有限。在对其生产工艺进行调整后,该公司认为可以将单台机器的周期缩减到20周,这样一来,每年的产能将达到45到50套系统。 今年的前三季度,ASML已经出货了23台EUV光刻机,预计全年销售量比2020年原计划的35台少一点。截至目前,ASML已累计出货83台商用EUV光刻机(其中包括2015年第一季度至2020年第三季度销售的NXE:3350B、NXE:3400B和NXE:3400C)。如果台积电官方关于拥有全球已安装和运行Twinscan NXE光刻机中约50%这个说法是正确的,那么目前可能已经拥有30至40台EUV光刻机。 台积电当然不是唯一采购大量EUV光刻机的半导体制造商。三星目前只使用EUV工艺来生产其7LPP和5LPE SoC以及一些DRAM,但随着三星晶圆厂扩大EUVL工艺在生产上的应用,三星半导体也提高了基于EUV工艺的DRAM的生产,最终将不可避免地采购更多的Twinscan NXE光刻机。预计英特尔也将在2022年开始使用其7nm节点生产芯片时,将开始部署EUVL设备,很可能在未来几年成为EUVL设备的主要采用者之一。 未来几年全球对EUV光刻机的需求只会增加,但从目前的情况来看,在未来一段时间内,台积电仍将是这些光刻设备的主要采购者,三星和英特尔将紧随其后。虽然说现在台积电在制造技术上面已经在世界稳居第一,但是台积电还是非常依赖光刻机的,要是在短时间内无法达到生产效率,即便光刻机数量增多也无法解决问题。