那曲檬骨新材料有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

實戰篇:IO設備

冬至子 ? 來源:編程外星人 ? 作者:怪蛙 ? 2023-10-11 10:13 ? 次閱讀

通常我們認為以計算機CPU為核心,其外部的所有的設備都可以稱為是外部輸入輸出設備。例如計算機中的顯示器就是一個輸出設備,它的作用是將一些數字信號轉化為圖形信號顯示在電子屏幕上,其數據是由內向外流動,因此我們稱顯示器為輸出設備。

又如鍵盤和鼠標是輸入設備,它們的作用是將使用者的命令信號轉化為數字信號傳遞給計算機的CPU,其數據是由外向內流動,因此我們稱鍵盤和鼠標為輸入設備。又如,打印機是一個輸出設備,游戲手柄和攝像頭是輸入設備。如下圖:

圖片

通常的,我們將鍵盤稱為計算機的標準輸入設備,將顯示器稱為計算機的標準輸出設備。這也是Unix和類Unix系統中一直延用的名稱。我們在做虛擬文件系統時將每一個進程中都分配了一個文件描述結構體數組:

//進程控制塊Process Control Block
typedef struct pcb_s
{
  //進程棧頂地址
  void *p_stack;
  //棧內存地址,釋放、統計內存時使用
  void *p_stack_mem;
  //棧內在大小
  uint32_t stack_size; 
  //優先級由高0到低32
  uint8_t prio;
  //任務狀態
  uint8_t status;
  //任務休眠ticks
  uint32_t sleep_tick;
  //任務入口函數
  void (*task_entry)(void *);
  //任務函數參數
  void *task_arg;
  //進程的文件描位圖,1表示空閑,0表示使用
  uint32_t f_use_map;
  //進程的文件描述結構體數組
  vfs_node_s *fnodes[FNODE_SIZE];
} pcb_s;

這個fnodes[FNODE_SIZE]文件描述數組記錄了進程所打開每一個設備文件的地址。這個數組的下標就是我們使用open()函數所返回的值,也就是我們通常所說的文件描述符。文件描述符為int類型,范圍通常是0~FNODE_SIZE。當文件描述符小于0時表示打開設備文件失敗。幾乎所有的類Unix系統中都使用了標準輸入、標準輸出和標準錯誤這3個IO設備。

所以,操作系統為每一個進程分配文件描述符時,會默認將0、1、2分別用于表示標準輸入、標準輸出和標準錯誤這3個設備。所以通常情況下我們使用open()函數來打開一個設備文件時, 返回的文件描述大多數是以3開始的,在同一個進程中同時打開多個設備文件,其文件描述符通常會是3、4、5、6、7、8……等。

實際上,我們在嵌入式領域里的處理器性能有限,外設的各類和功能多種多樣,并非像個人電腦或是網絡服務器一樣通用和統一。在單片機領域中我們所使用的操作系統并非一定要遵循Unix標準或習慣,但為了學習其優秀的設計理念,我們可以將我們的嵌入式操作系統中實現標準輸入、標準輸出和標準錯誤這3個設備。

在Cortex-M3處理器中我們可以使用串口設備作為操作系統中的標準輸入和標準輸出,而從本質上講標準錯誤這個設備的功能跟標準輸出是一樣的,只不過其顯示的內容都是程序錯誤,我們不單獨來實現標準錯誤設備,而只來完成標準輸入和標準輸出這兩個設備。例如串口1的初始化、讀、寫程序如下:

void serial1_init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  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;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  USART_InitStructure.USART_BaudRate = SERIAL_BAUTRATE;
  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;
  USART1- >CR1 |= (USART_CR1_RE | USART_CR1_TE);
  USART_Init(USART1, &USART_InitStructure);
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  USART_Cmd(USART1, ENABLE);
}


void serial1_write(uint8_t data)
{
  uint8_t next_head = serial1_tx_buffer_head + 1;
  if (next_head >= TX_RING_BUFFER1)
  {
    next_head = 0;
  }
  while (next_head == serial1_tx_buffer_tail);
  serial1_tx_buffer[serial1_tx_buffer_head] = data;
  serial1_tx_buffer_head = next_head;
  USART1- >CR1 |= USART_FLAG_TXE;
}


int serial1_read(uint8_t *ch)
{
  uint8_t tail = serial1_rx_buffer_tail;
  if (serial1_rx_buffer_head == tail)
  {
    return 0;
  }
  else
  {
    uint8_t data = serial1_rx_buffer[tail];
    tail++;
    if (tail >= RX_RING_BUFFER1)
    {
      tail = 0;
    }
    serial1_rx_buffer_tail = tail;
    *ch = data;
    return 1;
  }
}


void storeHandleDataIn(uint8_t data)
{
  uint8_t next_head;  
  next_head = serial1_rx_buffer_head + 1;
  if (next_head >= RX_RING_BUFFER1)
  {
    next_head = 0;
  }
    if (next_head != serial1_rx_buffer_tail)
  {
    serial1_rx_buffer[serial1_rx_buffer_head] = data;
    serial1_rx_buffer_head = next_head;
  }
  else
  {
    next_head++;
    next_head--;
  }
}

之后我們就可以編寫一個/dev/ttyS1設備文件用于串口1的驅動:

int ttyS1_open(struct file *fs)
{
  return 0;
}


int ttyS1_close(struct file *fs)
{
  return 0;
}


size_t ttyS1_read(struct file *fs, void *buff, size_t size)
{
  uint8_t *p = (uint8_t *)buff;
  size_t read_len = 0;
  for (int i = 0; i < size; i++)
  {
    if (!serial1_read(&p[read_len]))
    {
      return read_len;
    }
    read_len++;
  }
  return size;
}


size_t ttyS1_write(struct file *fs, const void *buff, size_t size)
{
  uint8_t *p = (uint8_t *)buff;
  for (int i = 0; i < size; i++)
  {
    serial1_write(p[i]);
  }
  return size;
}


void ttyS1_init(void)
{
  file_operations_s ops = {0};


  ops.open = ttyS1_open;
  ops.close = ttyS1_close;
  ops.write = ttyS1_write;
  ops.read = ttyS1_read;
  ops.ioctl = NULL;


  fs_register_dev("/dev/ttyS1", ops);
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 處理器
    +關注

    關注

    68

    文章

    19349

    瀏覽量

    230296
  • 計算機
    +關注

    關注

    19

    文章

    7520

    瀏覽量

    88233
  • Unix系統
    +關注

    關注

    0

    文章

    15

    瀏覽量

    9680
  • Cortex-M3
    +關注

    關注

    9

    文章

    270

    瀏覽量

    59509
  • 串口輸出
    +關注

    關注

    0

    文章

    16

    瀏覽量

    7513
收藏 人收藏

    評論

    相關推薦

    力天手把手教你學單片機視頻全集下載

    .rarhttp://115.com/file/e7fv6828#17.第九講.輸出型外設與51的IO口上--力天手把手教你學單片機之實戰篇.rarhttp://115.com/file
    發表于 02-14 17:06

    小七免殺論壇vip 2013源碼免殺培訓課程

    實戰篇----瑞星還能再低調么?第十三課:源碼免殺實戰篇----江民這是腫么了.第十四課:源碼免殺實戰篇----諾頓(百度說你是世界三大殺毒哇)第十五課:源碼免殺實戰篇----AVG(
    發表于 10-05 17:35

    【連載貼】【NetRotuer之像學單片機一樣學linux筆記】一、目錄

    1.8.2寫一個頁面配置系統 1.8.3頁面數據與服務器交互 1.8.4php以及lighttpd安裝1.9. 實戰篇之串口轉wifi2.0. 實戰篇之wifi讀卡器 2.1.實戰篇之點陣廣告系統 2.2
    發表于 02-16 17:38

    【IMX6UL開發板試用體驗】- 項目前 - USB 設備驅動實戰篇

    函數,當然拔掉設備自然是運行我們的disconnect ,最后根據判斷的語句對USB 設備的各個端口進行打印。結果如下:因為這是 實戰的前,所以不過多的講解,而在后面安排了用USB接
    發表于 03-07 23:06

    《HELLO+FPGA》-+項目實戰篇

    《HELLO+FPGA》-+項目實戰篇
    發表于 09-27 10:08

    【電子書】《HELLO FPGA》- 項目實戰篇

    `項目實戰篇以例舉三人表決器、數字時鐘、多終端點歌系統、數字示波器這四個實際的工程項目,手把手帶領大家從分析工程、分解工程到最終實現工程。`
    發表于 04-06 14:20

    如何開發符合AUTOSAR規范的電機控制器軟件

    基于AUTOSAR規范的電機控制器軟件開發本系列文章主要介紹如何開發符合AUTOSAR規范的電機控制器軟件的詳細過程。全系類分為基礎實戰篇:基礎內簡要介紹最新的AUTOSAR規范,嵌入式
    發表于 08-30 08:59

    Linux和RTOS的時鐘和定時器怎么使用

    定時器1.7初始化和脫離定時器1.8啟動和停止定時器1.9高精度延時1.10實戰篇:RTOS定時器代碼演示2Linux2.1Linux簡介2.2Linux定時器機制2.3alarm類定時器2.4進程
    發表于 01-17 08:13

    觸摸按鍵控制LED學習筆記

    實戰篇_流水燈第17節:實戰篇_按鍵控制LED第18節:實戰篇_按鍵控制蜂鳴器(按鍵消抖)第19節:實戰篇_觸摸按鍵控制LED第20節:實戰篇
    發表于 02-24 06:24

    筆記本無線上網之實戰篇

    筆記本無線上網之實戰篇 無線上網實戰篇   考慮到CDMA1X方式速率方面以及技術上、功能上比GPRS更先進,
    發表于 01-18 11:14 ?347次閱讀

    項目實戰篇

    項目實戰篇,VHDL資料,又需要的下來看看
    發表于 08-08 17:03 ?92次下載

    HELLO FPGA項目實戰篇的PDF電子書免費下載

    項目實戰篇包含哪些內容:我們例舉三人表決器、數字時鐘、多終端點歌系統、數字示波器這四個實際的工程項目,手把手帶領大家從分析工程、分解工程、到最終實現工程。通過逐個解決工程中的實際問題,來學習原汁原味
    發表于 06-01 08:00 ?15次下載
    HELLO FPGA項目<b class='flag-5'>實戰篇</b>的PDF電子書免費下載

    劉潤5分鐘商學院之實戰篇電子版下載

    劉潤5分鐘商學院之實戰篇電子版下載
    發表于 09-03 16:31 ?0次下載

    【單片機】實戰篇:Keil+Proteus數碼管計數99

    【征服單片機】實戰篇:Keil+Proteus數碼管計數99本篇文章:主要內容:靜態點亮數碼管顯示數字99、動態點亮數碼管顯示12345678(8位數碼管)。功能一:靜態點亮數碼管顯示數字99(2位數碼管)功能二:動態點亮數碼管顯示12345678(8位數碼管)
    發表于 11-23 17:36 ?17次下載
    【單片機】<b class='flag-5'>實戰篇</b>:Keil+Proteus數碼管計數99

    INTEL FPGA學習筆記

    實戰篇_流水燈第17節:實戰篇_按鍵控制LED第18節:實戰篇_按鍵控制蜂鳴器(按鍵消抖)第19節:實戰篇_觸摸按鍵控制LED第20節:實戰篇
    發表于 12-31 19:54 ?15次下載
    INTEL FPGA學習筆記
    网络百家乐官网证据| 百家乐官网筹码套装| 浩博百家乐娱乐城| 百家乐官网小77论坛| 澳门百家乐打法精华| 百家乐官方网站| 百家乐博彩策略| 大发888 配置要求| 投真钱百家乐必输吗| 百家乐官网变牌器| 百家乐官网tt娱乐| 大发888免费软件下载| 免费百家乐的玩法技巧和规则| 百家乐游戏排行榜| 百家乐官网庄闲和收益| 百家乐官网视频游戏平台| 大发888打不开| 中华百家乐的玩法技巧和规则 | 改则县| 百家乐园百乐彩| 澳门百家乐现场游戏| 百家乐官网玩揽法的论坛| 百家乐官网技巧和规律| 大发888城官方下载| 百家乐连锁| 新东方百家乐官网的玩法技巧和规则 | 百家乐的出牌技巧| 缅甸百家乐官网网站是多少| 百家乐官网里和的作用| 中国足球竞彩网| 百家乐太阳娱乐网| VIP百家乐-挤牌卡安桌板| 子山午向的房子24山图| 百家乐官网赌场论坛| 秦安县| 本溪棋牌网| 博彩网站排名| 波克棋牌游戏大厅下载| 百家乐作弊| 顶级赌场真假的微博| 大庆冠通棋牌下载|