zoukankan      html  css  js  c++  java
  • 基于s3c2440的12864液晶驱动

    12864是128*64点阵液晶模块的点阵数简称,业界约定俗成的简称。

    一、液晶显示模块概述
    12864A-1 汉字图形点阵液晶显示模块,可显示汉字及图形,内置 8192 个中文汉字(16X16 点阵,16*8=128,16*4=64,一行只能写 8 个汉字,4 行;、128 个字符(8X16 点阵)及 64X256 点阵显示 RAM(GDRAM))。
    主要技术参数和显示特性:
    电源:VDD 3.3V~+5V(内置升压电路,无需负压);
    显示内容:128 列× 64 行(128 表示点数)
    显示颜色:黄绿
    显示角度:6:00 钟直视
    LCD 类型:STN
    与 MCU 接口:8 位或 4 位并行/3 位串行
    配置 LED 背光
    多种软件功能:光标显示、画面移位、自定义字符、睡眠模式等

    引脚定义:D0-D7,RS,RES,RD,WR,CS,BL;具体头文件定义如下:

    #ifndef LCD12864_H
    #define LCD12864_H

    #define LCD12864_MAJOR 242
    #define DEV_NAME "lcd12864"

    #define LCD12864_IOCTL 'l'
    #define SET_FONT_SIZE _IOW(LCD12864_IOCTL,0 ,unsigned int)
    #define SET_LCD_PAGE _IOW(LCD12864_IOCTL,1 ,unsigned int)
    #define SET_LCD_COLUMN _IOW(LCD12864_IOCTL,2 ,unsigned int)
    #define CLR_SCREEN _IOW(LCD12864_IOCTL,3 ,unsigned int)
    #define BACKLIGHT_CTRL _IOW(LCD12864_IOCTL,4 ,unsigned int)
    #define CONTRAST_SETTING _IOW(LCD12864_IOCTL,5 ,unsigned int)

    #define LCD_DATA_0 S3C2410_GPC8
    #define LCD_DATA_1 S3C2410_GPC9
    #define LCD_DATA_2 S3C2410_GPC10
    #define LCD_DATA_3 S3C2410_GPC11

    #define LCD_DATA_4 S3C2410_GPC12
    #define LCD_DATA_5 S3C2410_GPC13
    #define LCD_DATA_6 S3C2410_GPC14
    #define LCD_DATA_7 S3C2410_GPC15


    #define LCD_E_RD S3C2410_GPD0
    #define LCD_RW_WR S3C2410_GPD1
    #define LCD_RS S3C2410_GPD2
    #define LCD_RES S3C2410_GPD3
    #define LCD_CS1 S3C2410_GPD4
    #define LCD_BL S3C2410_GPD5


    #define LCD_DATA_CFG0_OUTP S3C2410_GPC8_OUTP
    #define LCD_DATA_CFG1_OUTP S3C2410_GPC9_OUTP
    #define LCD_DATA_CFG2_OUTP S3C2410_GPC10_OUTP
    #define LCD_DATA_CFG3_OUTP S3C2410_GPC11_OUTP

    #define LCD_DATA_CFG4_OUTP S3C2410_GPC12_OUTP
    #define LCD_DATA_CFG5_OUTP S3C2410_GPC13_OUTP
    #define LCD_DATA_CFG6_OUTP S3C2410_GPC14_OUTP
    #define LCD_DATA_CFG7_OUTP S3C2410_GPC15_OUTP


    #define LCD_E_RD_CFG_OUTP S3C2410_GPD0_OUTP
    #define LCD_RW_WR_CFG_OUTP S3C2410_GPD1_OUTP
    #define LCD_RS_CFG_OUTP S3C2410_GPD2_OUTP
    #define LCD_RES_CFG_OUTP S3C2410_GPD3_OUTP
    #define LCD_CS1_CFG_OUTP S3C2410_GPD4_OUTP
    #define LCD_BL_CFG_OUTP S3C2410_GPD5_OUTP


    #define FONT_SIZE_8 8
    #define FONT_SIZE_16 16


    #endif

    将引脚单独用头文件重新自己定义一次,以提高代码的可移植性。

    下面看看模块初始化/释放函数:

    static int __init lcd12864_init(void)
    {
    int ret;
    dev_t devno;

    DBPRINTF(KERN_ALERT
    "%s enter!\n",__func__);
    devno
    = MKDEV(lcd12864_major,0);
    if((ret = register_chrdev_region(devno,1,DEV_NAME))<0)
    {
    if((ret = alloc_chrdev_region(&devno, 0, 1, DEV_NAME))<0)
    {
    DBPRINTF(KERN_ALERT
    "chrdev region fail!ret=%d;\n",ret);
    return ret;
    }
    else
    {
    lcd12864_major
    = MAJOR(devno);
    }
    }
    cdev_init(
    &lcd_cdev, &lcd12864_ops);
    lcd_cdev.owner
    =THIS_MODULE;
    lcd_cdev.ops
    = &lcd12864_ops;

    ret
    = cdev_add(&lcd_cdev, devno, 1);
    if(ret<0)
    {
    goto fail_reg;
    }

    lcd_dev_class
    = class_create(THIS_MODULE, DEV_NAME);
    if(IS_ERR(lcd_dev_class))
    {
    goto fail_cdev;
    }
    device_create(lcd_dev_class, NULL, devno, NULL, DEV_NAME);

    lcd_bd_info
    = kmalloc(sizeof(struct lcd_board_info),GFP_KERNEL);
    lcd_bd_info
    ->font_size = 16;

    #ifdef NORMAL
    lcd_bd_info
    ->pag = 0;
    lcd_bd_info
    ->column = 0;
    #else
    lcd_bd_info
    ->pag = 6;
    lcd_bd_info
    ->column = 112;
    #endif
    lcd_bd_info
    ->lcd_data_t = lcd_data_table;
    lcd_bd_info
    ->lcd_data_cfg_t = lcd_data_cfg_table;

    spin_lock_init(
    &lock);

    gpio_pin_init();
    //gpio_pin_init();


    ret
    = init_lcd12864();
    if(ret<0)
    {
    goto fail_dev;
    }
    back_light_ctrl(
    1);
    clear_lcd_screen(
    0x00);
    DBPRINTF(KERN_ALERT
    "%s leave,init success!\n",__func__);
    return ret;

    fail_dev:
    device_destroy(lcd_dev_class, devno);
    class_destroy(lcd_dev_class);

    fail_cdev:
    cdev_del(
    &lcd_cdev);
    fail_reg:
    unregister_chrdev_region(devno,
    1);
    return ret;
    }


    static void __exit lcd12864_exit(void)
    {
    kfree(lcd_bd_info);
    device_destroy(lcd_dev_class, MKDEV(lcd12864_major,
    0));
    class_destroy(lcd_dev_class);
    cdev_del(
    &lcd_cdev);
    unregister_chrdev_region(MKDEV(lcd12864_major,
    0), 1);
    }

    module_init(lcd12864_init);
    module_exit(lcd12864_exit);

    MODULE_LICENSE(
    "GPL");
    MODULE_AUTHOR(
    "HOY");
    MODULE_DESCRIPTION(
    "gonsin 128x64 lcd driver");

    以上主要工作是:通过register_chrdev_region静态分配设备号devno,如果分配失败,则通过系统alloc_chrdev_region动态分配;

    此处通过cdev创建字符设备;通过cdev_add添加入系统中。通过class_create和device_create生成并注册一个逻辑设备,通过此工作,可以在/dev/下面看到设备名;

    初始化lcd_board_info结构,lcd_board_info结构定义如下:

    struct lcd_board_info{

    unsigned
    int font_size;
    unsigned
    int pag;
    unsigned
    int column;
    unsigned
    long* lcd_data_t;
    unsigned
    long* lcd_data_cfg_t;
    };

    static struct lcd_board_info* lcd_bd_info;

    其他变量和头文件定义如下:

    #include <linux/fs.h>
    #include
    <linux/module.h>
    #include
    <linux/init.h>
    #include
    <mach/regs-gpio.h>
    #include
    <linux/ioctl.h>
    #include
    <linux/cdev.h>
    #include
    <linux/slab.h>
    #include
    <linux/uaccess.h>
    #include
    <linux/device.h>
    #include
    <asm/io.h>
    #include
    <linux/delay.h>

    #define DEBUG //调试状态
    #ifdef DEBUG
    #define DBPRINTF(fmt,args...) printk(KERN_ALERT "lcd:" fmt, ##args)
    #else
    #define DBPRINTF(fmt,args...)
    #endif

    #include
    "lcd_12864.h"

    #define NORMAL //正常模式


    static struct class* lcd_dev_class;

    struct cdev lcd_cdev;

    static int lcd12864_major = LCD12864_MAJOR;

    static unsigned long lcd_data_table[]={
    LCD_DATA_0,
    LCD_DATA_1,
    LCD_DATA_2,
    LCD_DATA_3,

    LCD_DATA_4,
    LCD_DATA_5,
    LCD_DATA_6,
    LCD_DATA_7,
    };

    /**/
    static unsigned long lcd_data_cfg_table[] =
    {
    LCD_DATA_CFG0_OUTP,
    LCD_DATA_CFG1_OUTP,
    LCD_DATA_CFG2_OUTP,
    LCD_DATA_CFG3_OUTP,

    LCD_DATA_CFG4_OUTP,
    LCD_DATA_CFG5_OUTP,
    LCD_DATA_CFG6_OUTP,
    LCD_DATA_CFG7_OUTP,
    };

    /*
    static unsigned char io_read_byte()
    {

    }
    */
    spinlock_t
    lock;

    然后调用以下函数进行gpio引脚的初始化、液晶屏的初始化:

    static int gpio_pin_init(void)
    {

    int ii;
    s3c2410_gpio_cfgpin(LCD_CS1, LCD_CS1_CFG_OUTP);
    s3c2410_gpio_cfgpin(LCD_RES, LCD_RES_CFG_OUTP);
    s3c2410_gpio_cfgpin(LCD_RS, LCD_RS_CFG_OUTP);
    s3c2410_gpio_cfgpin(LCD_RW_WR, LCD_RW_WR_CFG_OUTP);
    s3c2410_gpio_cfgpin(LCD_E_RD, LCD_E_RD_CFG_OUTP);
    s3c2410_gpio_cfgpin(LCD_BL, LCD_BL_CFG_OUTP);

    for(ii=0; ii<8; ii++)
    {
    s3c2410_gpio_cfgpin(lcd_bd_info
    ->lcd_data_t[ii], lcd_bd_info->lcd_data_cfg_t[ii]);
    }
    return 0;
    }


    static unsigned char init_cmd[]={
    0xe2,
    0xa0,
    0xc0,
    0xA2,
    0x2B,
    0x2E,
    0x2F,
    0x27,
    0xAF,
    0,
    };


    static int init_lcd12864(void)
    {

    int ii;
    s3c2410_gpio_setpin(LCD_CS1,
    0);
    udelay(
    500);
    s3c2410_gpio_setpin(LCD_RES,
    0);
    udelay(
    500);
    s3c2410_gpio_setpin(LCD_RES,
    1);
    udelay(
    500);

    for(ii=0;init_cmd[ii]!=0;ii++)
    {
    send_cmd(init_cmd[ii]);
    udelay(
    50);
    }
    return 0;
    }

    以下为写液晶屏和写命令的操作:

    #ifdef NORMAL
    /*往液晶中写入1个字符数据*/
    static void io_write_byte(unsigned char data)
    {
    unsigned
    char ii;
    spin_lock(
    &lock);

    for(ii=0;ii<8;ii++)
    {
    if(data&0b1)
    {
    s3c2410_gpio_setpin(lcd_bd_info
    ->lcd_data_t[ii], 1);
    }
    else
    {
    s3c2410_gpio_setpin(lcd_bd_info
    ->lcd_data_t[ii], 0);
    }
    data
    = data>>1;
    }
    //__raw_writel(((__raw_readl(S3C2410_GPCDAT)&~(0xff<<8))|(data<<8)),S3C2410_GPCDAT);

    spin_unlock(
    &lock);

    s3c2410_gpio_setpin(LCD_RS,
    1);
    s3c2410_gpio_setpin(LCD_RW_WR,
    0);
    s3c2410_gpio_setpin(LCD_E_RD,
    1);
    s3c2410_gpio_setpin(LCD_CS1,
    1);
    udelay(
    1);
    s3c2410_gpio_setpin(LCD_CS1,
    0);
    udelay(
    1);

    }
    #else
    static void io_write_byte(unsigned char data)
    {
    unsigned
    char ii;
    spin_lock(
    &lock);
    for(ii=0;ii<8;ii++)
    {
    if(data&0x80)
    {
    //DBPRINTF(KERN_ALERT "[||||||||||||||||||||]\n");
    s3c2410_gpio_setpin(lcd_bd_info->lcd_data_t[ii], 1);
    }
    else
    {
    //DBPRINTF(KERN_ALERT "[--------------------]\n");
    s3c2410_gpio_setpin(lcd_bd_info->lcd_data_t[ii], 0);
    }
    data
    = data<<1;
    }
    spin_unlock(
    &lock);
    //DBPRINTF(KERN_ALERT "\n");

    s3c2410_gpio_setpin(LCD_RS,
    1);
    s3c2410_gpio_setpin(LCD_RW_WR,
    0);
    s3c2410_gpio_setpin(LCD_E_RD,
    1);

    s3c2410_gpio_setpin(LCD_CS1,
    1);
    udelay(
    1);
    s3c2410_gpio_setpin(LCD_CS1,
    0);
    udelay(
    1);
    }
    #endif

    //发送命令
    static int send_cmd(unsigned char cmd)
    {
    int ii;
    unsigned
    char tmp;
    tmp
    = 0x00;
    spin_lock(
    &lock);

    for(ii=0;ii<8;ii++)
    {
    if(cmd&0x80)
    {
    s3c2410_gpio_setpin(lcd_bd_info
    ->lcd_data_t[ii], 1);
    }
    else
    {
    s3c2410_gpio_setpin(lcd_bd_info
    ->lcd_data_t[ii], 0);
    }
    cmd
    = cmd<<1;
    }
    /*******************/
    /*
    for(ii=0;ii<8;ii++)
    {
    tmp = tmp<<1;
    if(cmd&0b1)
    {
    tmp|=0b1;
    }
    else
    {
    tmp &= 0b0;
    }
    cmd = cmd>>1;

    }
    __raw_writel(((__raw_readl(S3C2410_GPCDAT)&~(0xff<<8))|(tmp<<8)),S3C2410_GPCDAT);
    */
    /*******************/

    spin_unlock(
    &lock);


    s3c2410_gpio_setpin(LCD_RS,
    0);
    s3c2410_gpio_setpin(LCD_RW_WR,
    0);
    s3c2410_gpio_setpin(LCD_E_RD,
    1);
    s3c2410_gpio_setpin(LCD_CS1,
    1);
    udelay(
    1);

    s3c2410_gpio_setpin(LCD_CS1,
    0);
    udelay(
    1);
    return 0;
    }



    static int dev_write_data(const char* data)
    {
    unsigned
    char dl,dh;
    int i,j;
    spin_lock(
    &lock);
    dh
    = lcd_bd_info->column/16;
    dl
    = lcd_bd_info->column-dh*16;
    for(i=0; i<2; i++)
    {
    send_cmd(
    0xB7-i-lcd_bd_info->pag);
    send_cmd(
    0x10+dh);
    send_cmd(dl);

    #ifdef NORMAL
    for(j=0;j<16;j++)
    io_write_byte(data[lcd_bd_info
    ->font_size*i+j]);
    #else
    for(j=0;j<16;j++)
    io_write_byte(data[lcd_bd_info
    ->font_size*(1-i)+(15-j)]);
    #endif
    }
    spin_unlock(
    &lock);
    return 0;
    }

    因为公司结构方面的需要,要将液晶倒转显示,所以此处做了两个不同的方案,如果定义了NORMAL,则正常显示,否则倒转显示;

    其他对液晶屏控制的操作如下:

    /*清除屏幕*/
    static void clear_lcd_screen(unsigned char clr_data)
    {
    unsigned
    char page_addr = 0xb7;
    unsigned
    int page_num;
    int ii;
    for(page_num=0; page_num<8; page_num++)
    {
    send_cmd(page_addr);
    send_cmd(
    0x10);
    send_cmd(
    0x00);
    for(ii=0; ii<128; ii++)
    io_write_byte(clr_data);
    page_addr
    --;
    }
    }

    static int lcd12864_open(struct inode* inode, struct file* filp)
    {
    return 0;
    }

    static int lcd12864_release(struct inode* inode, struct file* filp)
    {
    return 0;
    }

    static ssize_t lcd12864_write(struct file* filp, char __user* buf, size_t size, loff_t offset)
    {
    char* kbuf;
    // int count;

    kbuf
    = kmalloc(size, GFP_KERNEL);
    copy_from_user(kbuf, buf, size);
    dev_write_data(kbuf);

    kfree(kbuf);
    return 0;
    }

    static int contrast_setting(int val)
    {
    if((val&0xff)>0x3e)
    return -1;
    send_cmd(
    0x81);
    send_cmd(val
    &0xff);
    DBPRINTF(KERN_ALERT
    "contrast setting,val is%d\n",val);
    return 0;
    }
    /*背光控制*/
    static int back_light_ctrl(int bl)
    {
    if(bl<0)
    {
    return -1;
    }
    else if(bl==0)
    {
    s3c2410_gpio_setpin(LCD_BL,
    0);
    DBPRINTF(KERN_ALERT
    "back light set value is 0\n");
    }
    else
    {
    s3c2410_gpio_setpin(LCD_BL,
    1);
    DBPRINTF(KERN_ALERT
    "back light set value is 1\n");
    }
    return 0;
    }

    static int lcd12864_ioctl(struct inode* inode,struct file* filp, unsigned int cmd, unsigned long args)
    {
    int ret;
    spin_lock(
    &lock);
    ret
    = 0;
    DBPRINTF(KERN_ALERT
    "%s",__func__);
    switch(cmd)
    {
    case SET_FONT_SIZE:
    {
    int size = *(int*)args;
    if(size == FONT_SIZE_8||size == FONT_SIZE_16)
    {
    lcd_bd_info
    ->font_size = size;
    }
    else
    {
    ret
    = -1;
    DBPRINTF(KERN_ALERT
    "set font size fail!\n");
    goto ioctl_fail;
    }
    break;
    }
    case SET_LCD_PAGE:
    {
    int tmp = *(int*)args;
    if(tmp>63)
    return -1;


    #ifdef NORMAL
    lcd_bd_info
    ->pag = tmp;
    #else
    lcd_bd_info
    ->pag = 6-tmp;
    #endif
    DBPRINTF(KERN_ALERT
    "set pag is %d\n",lcd_bd_info->pag);
    break;
    }
    case SET_LCD_COLUMN:
    {
    int tmp = *(int*)args;
    if(tmp>127)
    return -1;
    #ifdef NORMAL
    lcd_bd_info
    ->column =tmp;
    #else
    lcd_bd_info
    ->column =112-tmp;
    #endif
    DBPRINTF(KERN_ALERT
    "set column is %d\n",lcd_bd_info->column);
    break;
    }
    case CLR_SCREEN:
    {
    unsigned
    char data = *(char*)args;
    clear_lcd_screen(data);
    break;
    }
    case BACKLIGHT_CTRL:
    {
    int bl = *(int*)args;
    ret
    = back_light_ctrl(bl);
    break;
    }
    case CONTRAST_SETTING:
    {
    int con = *(int*)args;
    ret
    = contrast_setting(con);
    break;
    }

    }
    spin_unlock(
    &lock);
    return ret;
    ioctl_fail:
    spin_unlock(
    &lock);
    return ret;
    }

    最后看看file_operations结构体:

    static struct file_operations lcd12864_ops={
    .owner
    = THIS_MODULE,
    .open
    = lcd12864_open,
    .release
    = lcd12864_release,
    .write
    = lcd12864_write,
    //.read = lcd12864_read,
    .ioctl = lcd12864_ioctl,
    };

    以上则是液晶屏的驱动程序,很简单吧?哈哈~~

    Makefile如下所示:

    obj-m:=lcd_12864.o
    KDIR
    =/home/project/linux-res/linux-2.6.30.4/

    all:
    $(MAKE)
    -C $(KDIR) M=$(PWD)

    .PHONY:clean
    clean:
    rm
    -f *.o *.ko *.mod.c *.mod.o *.tmp_versions

    最后是液晶屏测试程序:

    enum {
    FONT_SIZE8,
    FONT_SIZE16,
    FONT_SIZE32,
    };


    /*将字符数组里面的每一位取反*/
    void oppersite(const char* cin, __out char* cout,int len)
    {
    int i=0;

    for(i=0;i<len;i++)
    {
    cout[i]
    =~cin[i];
    }
    }

    /*由size_flag 解析出字体大小*/
    int prase_size_flag(int size_flag)
    {
    int fsize;
    switch(size_flag)
    {
    case FONT_SIZE8:
    fsize
    = 8;
    break;
    case FONT_SIZE16:
    fsize
    = 16;
    break;
    case FONT_SIZE32:
    fsize
    = 32;
    break;
    default:
    printf(
    "size_flag is involid!\n");
    return -1;
    }
    return fsize;
    }

    int prase_row(int pag)
    {
    return pag*2;
    }

    int prase_column(int col)
    {
    return col*16;
    }

    /*显示一个选中的字符
    ch:字符的16进制数组
    pag:第几页;0-7
    col:第几列;0-127
    size_flag:字体枚举
    */
    int show_select_ch(int fd, const char* ch, int pag, int col, int size_flag)
    {
    char chtmp[50];
    int fsize;

    if(!ch)
    return -1;

    if((fsize=prase_size_flag(size_flag))<0)
    return -1;

    int size = fsize*fsize/8;
    oppersite(ch, chtmp, size);
    if(ioctl(fd, SET_LCD_PAGE, &pag)<0)
    return -1;
    if(ioctl(fd, SET_LCD_COLUMN, &col)<0)
    return -1;
    if(write(fd, chtmp, size)<0)
    return -1;
    return 0;
    }
    /*显示一个字符
    ch:字符的16进制数组
    pag:第几页;0-7
    col:第几列;0-127
    size_flag:字体枚举
    */
    int show_ch(int fd, const char* ch, int pag, int col, int size_flag)
    {
    if(!ch)
    return -1;

    int fsize;
    if((fsize=prase_size_flag(size_flag))<0)
    return -1;

    int size = fsize*fsize/8;
    if(ioctl(fd, SET_LCD_PAGE, &pag)<0)
    return -1;
    if(ioctl(fd, SET_LCD_COLUMN, &col)<0)
    return -1;
    if(write(fd, ch, size)<0)
    return -1;
    return 0;
    }

    /*显示一行字符串*/
    int show_str(int fd, const char** str, int count, int pag, int col, int size_flag)
    {
    int fsize;
    int i;
    if((fsize=prase_size_flag(size_flag))<0)
    return -1;

    for(i=0; i<count; i++)
    {
    if(pag<PAGE_COUNT && col<COLUMN_COUNT)
    {
    if(show_ch(fd, str[i], pag, col, size_flag)<0)
    return -1;
    col
    +=fsize;
    }
    }
    return 0;
    }

    /*显示一行选中的字符串*/
    int show_select_str(int fd, const char** str, int count, int pag, int col, int size_flag)
    {
    int fsize;
    int i;
    if((fsize=prase_size_flag(size_flag))<0)
    return -1;

    for(i=0; i<count; i++)
    {
    if(pag<PAGE_COUNT && col<COLUMN_COUNT)
    {
    if(show_select_ch(fd, str[i], pag, col, size_flag)<0)
    return -1;
    col
    +=fsize;
    }
    }
    return 0;
    }

    /*对比度调节0-62*/
    int contrast_ctrl(int fd, int val)
    {
    if(ioctl(fd,CONTRAST_SETTING,&val)<0)
    return -1;
    return 0;
    }

    /*背光调节 1:亮,0:灭*/
    int backlight_ctrl(int fd,int val)
    {
    if(ioctl(fd, BACKLIGHT_CTRL, &val)<0)
    return -1;
    return 0;
    }

    /*清屏*/
    int clear_screen(int fd, int val)
    {
    if(ioctl(fd, CLR_SCREEN, &val)<0)
    return -1;
    return 0;
    }


    /*字体大小*/
    int font_size(int fd, int val)
    {
    if(ioctl(fd, SET_FONT_SIZE, &val)<0)
    return -1;
    return 0;
    }
    int main(void)
    {
    fd
    = open(LCD_DEV_NAME,O_RDWR);
    show_ch(fd, zi,
    0, 0, 1);
    show_select_ch(fd, zi,
    0, 32, 1);
    show_str(fd, tmp,
    8, 2, 0, 1);
    show_select_str(fd, tmp,
    8, 4, 0, 1);
    close(fd);
    }
  • 相关阅读:
    OneProxy与其它数据库中间件的对比
    防御式编程
    google jam 比赛题(设计有问题)
    Python 代码性能优化技巧
    Python性能鸡汤
    如何避免重构带来的危险
    Linux/Unix工具与正则表达式的POSIX规范
    代码抽象层次2
    chinaunix:腾讯面试题
    C++异常处理小例
  • 原文地址:https://www.cnblogs.com/hoys/p/2024083.html
Copyright © 2011-2022 走看看