C#编程之C#上位机串口控制12864显示
小标 2019-03-13 来源 : 阅读 911 评论 0

摘要:本文主要向大家介绍了C#编程之C#上位机串口控制12864显示,通过具体的内容向大家展示,希望对大家学习C#编程有所帮助。

本文主要向大家介绍了C#编程之C#上位机串口控制12864显示,通过具体的内容向大家展示,希望对大家学习C#编程有所帮助。

C#编程之C#上位机串口控制12864显示

实现的效果
 

 
上面是用Proteus仿真的,,对了如果自己想用proteus仿真需要安装下面这个软件

 
再看一下实物显示效果
 

 

 
先做上位机部分...........

为了程序一启动就把电脑上能用的串口号显示在下拉框中
 

private void Form1_Load(object sender, EventArgs e)
        {
            string[] ComName = SerialPort.GetPortNames();//把可用的串口号存入comname
            comboBoxCom.Items.AddRange(ComName);//添加到下拉框
            comboBoxCom.SelectedIndex = comboBoxCom.Items.Count > 0 ? 0 : -1;//显示第一个
        }

还有就是串口呢可能会随时改变,所以在用户点击下拉框的时候重新更新一下下拉框中的内容

 private void comboBoxCom_DropDown(object sender, EventArgs e)
        {
            string[] ComName = SerialPort.GetPortNames();//把可用的串口号存入comname
            comboBoxCom.Items.Clear();//先清除一下,防止重复添加
            comboBoxCom.Items.AddRange(ComName);//添加到下拉框
            comboBoxCom.SelectedIndex = comboBoxCom.Items.Count > 0 ? 0 : -1;//显示第一个
        }

现在在波特率框中添加常用的波特率

现在的效果

然后放一个按钮用来打开和关闭串口

 现在就做打开和关闭串口部分,,,
 

/// <打开按钮事件>
        ///
        ///
        ///
        ///
        private void buttonOpen_Click(object sender, EventArgs e)
        {
            if (OpenFlage == false)//打开串口
            {
                try
                {
                    serialPort1.PortName = comboBoxCom.Text;//端口号
                    serialPort1.BaudRate = Convert.ToInt32(comboBoxBaud.Text);//波特率
                    serialPort1.Open();//打开串口
                    OpenFlage = true;
                }
                catch (Exception)//其余意外情况执行这里
                {
                    OpenFlage = false;
                    MessageBox.Show("端口错误,请检查串口", "提示");
                }
               
            }
            else//关闭串口
            {
                try
                {
                    OpenFlage = false;
                    if (serialPort1.IsOpen)//判断串口是否打开,如果打开执行下一步操作
                    {
                        serialPort1.Close();
                    }
                    serialPort1.Close();//强制关闭
                }
                catch (Exception)
                {
                }
               
            }
        }

对了按钮点击了打开串口,让它显示"关闭串口"
就用回调来显示

现在按钮事件就这样了

/// <打开按钮事件>
        ///
        ///
        ///
        ///
        private void buttonOpen_Click(object sender, EventArgs e)
        {
            if (OpenFlage == false)//打开串口
            {
                try
                {
                    serialPort1.PortName = comboBoxCom.Text;
                    serialPort1.BaudRate = Convert.ToInt32(comboBoxBaud.Text);
                    serialPort1.Open();
                    OpenFlage = true;
                    buttonOpen.Invoke(buttonConnectDelegate,"关闭串口");
                }
                catch (Exception)//其余意外情况执行这里
                {
                    OpenFlage = false;
                    buttonOpen.Invoke(buttonConnectDelegate, "打开串口");
                    MessageBox.Show("端口错误,请检查串口", "提示");
                }
               
            }
            else//关闭串口
            {
                try
                {
                    OpenFlage = false;
                    buttonOpen.Invoke(buttonConnectDelegate, "打开串口");
                    if (serialPort1.IsOpen)//判断串口是否打开,如果打开执行下一步操作
                    {
                        serialPort1.Close();
                    }
                    serialPort1.Close();//强制关闭
                }
                catch (Exception)
                {
                }
               
            }
        }

现在在多优化一下,我们在打开了串口的时候,我接着用去选择别的串口了,那么为了不去重复重新打开的按钮动作,我们就多加一点程序,,,,这个一会再说吧!现在看不出效果现在写接收程序部分
放一个textbox

接收的文本框设置只读

接收的数据肯定会很多,,所以让他有上下的滚动条

 
然后界面又加了几个按钮和选择

现在接收数据

为了接收到一条完整的数据之后再去做处理,我就用个定时器用于检测接收是否空闲了一段时间,只要出现空闲说明接收到了一条完整的数据

设置的是10ms检测一次
看程序里面怎么做,,,其实和我的单片机检测空闲是一样的道理
定义一个链表用于存储数据,还有两个计数变量

 ListSerialBuffer = new List(1024);//串口接收数据缓存
        int UsartReadCnt = 0;//串口接收到的数据个数
        int UsartIdleCnt = 0;//空闲检测用

串口接收函数里面这样写

 private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] SerialBuff = new byte[serialPort1.BytesToRead];//串口接收数据临时缓存
            if (serialPort1.BytesToRead != 0)
            {
                try
                {
                    UsartReadCnt = serialPort1.Read(SerialBuff, 0, serialPort1.BytesToRead);
                    SerialBuffer.AddRange(SerialBuff);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }

然后定时器里面

/// <串口空闲检测定时器>
        ///
        ///
        ///
        ///
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (UsartReadCnt != 0)//如果接收到数据了
            {
                if (UsartIdleCnt == UsartReadCnt)//10ms时间数据没了变化
                {
                    UsartReadCnt = 0;//清零数据个数
                    UsartIdleCnt = 0;//清零
                    byte[] ReadData = new byte[SerialBuffer.Count];
                    for (int i = 0; i < SerialBuffer.Count; i++)
                    {
                        ReadData[i] = SerialBuffer[i];
                    }
                    SerialBuffer.RemoveRange(0, SerialBuffer.Count);
                }
                else
                {
                    UsartIdleCnt = UsartReadCnt;
                }
            }
        }

现在定义个回调把数据显示出来

/// <显示串口接收到的信息>
        ///
        ///
        private void ShowReMsgMethod(byte[] by)
        {
           
        }

private void ShowReMsgMethod(byte[] by)
        {
            string getMsg = " ";
            if (checkBoxHexShow.Checked)//16进制显示
            {
                getMsg = byteToHexStr(by); //用到函数byteToHexStr--字节数组转16进制字符串
            }
            else
            {
                getMsg = new ASCIIEncoding().GetString(by);
            }
            textBoxDataRes.AppendText(getMsg);
        }

 /// <字节数组转16进制字符串>
        ///
        ///
        ///
        ///
        public static string byteToHexStr(byte[] bytes)
        {
            string returnStr = string.Empty;
            try
            {
                if (bytes != null)
                {
                    for (int i = 0; i < bytes.Length; i++)
                    {
                        returnStr += bytes[i].ToString("X2");
                    }
                }
                return returnStr;
            }
            catch (Exception)
            {
                return returnStr;
            }
        }

现在启动试一下

 
我电脑上安装了虚拟串口软件,方便调试

 
还有就是

当我们选择这个的时候希望接收框里面的内容也跟着改变
就像是这样

选择上

然后再取消选择

 
这样感觉更好一些

写上以下代码

 private void checkBoxHexShow_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxHexShow.Checked)
            {
                try
                {
                    byte[] by = StringToByte(textBoxDataRes.Text);
                    textBoxDataRes.Clear();
                    textBoxDataRes.BeginInvoke(showReMsgSerialDelegate, by);
                }
                catch (Exception ex)
                {
                    //MessageBox.Show(ex.ToString());
                }
            }
            else
            {
                try
                {
                    byte[] by = strToToHexByte(textBoxDataRes.Text);
                    textBoxDataRes.Clear();
                    textBoxDataRes.BeginInvoke(showReMsgSerialDelegate, by);
                }
                catch (Exception ex)
                {
                    //MessageBox.Show(ex.ToString());
                }
            }

其实就一句话..........................

 /// <字符串转换成字节数组>
       ///
       ///
       ///
       ///
        public static byte[] StringToByte(string stringToConvert)
        {
            return (new ASCIIEncoding()).GetBytes(stringToConvert);
        }

/// <字符串转16进制格式,不够自动前面补零(每两位组成一个16进制数)>
        ///
        ///
        ///
        ///
        private static byte[] strToToHexByte(String hexString)
        {
            int i;
            bool Flag = false;

            hexString = hexString.Replace(" ", "");//清除空格
            if ((hexString.Length % 2) != 0)
            {
                Flag = true;
            }
            if (Flag == true)
            {
                byte[] returnBytes = new byte[(hexString.Length + 1) / 2];

                try
                {
                    for (i = 0; i < (hexString.Length - 1) / 2; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, ‘0‘), 16);

                }
                catch
                {
                    for (i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = 0;
                    }
                    MessageBox.Show("超过16进制范围A-F,已初始化为0", "提示");
                }
                return returnBytes;
            }
            else
            {
                byte[] returnBytes = new byte[(hexString.Length) / 2];
                try
                {
                    for (i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                }
                catch
                {
                    for (i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = 0;
                    }
                    MessageBox.Show("超过16进制范围A-F,已初始化为0", "提示");
                }
                return returnBytes;
            }
        }

看效果

 

 
加一个功能,,,我已经电机打开一个串口了,然后呢想换一个

然而如果和第一次选择的一样就不切换了

 

写上以下代码

private void comboBoxCom_DropDownClosed(object sender, EventArgs e)
        {
            try
            {
                if (CopyPortName != comboBoxCom.SelectedItem.ToString())//与当前的不同才切换
                {
                    if (serialPort1.IsOpen)
                    {
                        serialPort1.Close();
                        serialPort1.PortName = comboBoxCom.SelectedItem.ToString();
                        serialPort1.BaudRate = Convert.ToInt32(comboBoxBaud.Text);
                        serialPort1.Open();                        CopyPortName = serialPort1.PortName;
                    }
                }
            }
            catch (Exception)//切换出现错误执行这里
            {
                OpenFlage = false;
                buttonOpen.Invoke(buttonConnectDelegate, "打开串口");
                MessageBox.Show("端口错误,请检查串口", "提示");
            }
        }

然后呢波特率也是如此不过呢有点不同

不用关闭串口....

private void comboBoxBaud_DropDownClosed(object sender, EventArgs e)
        {
            try
            {
                if (CopyBaud != Convert.ToInt32(comboBoxBaud.SelectedItem.ToString()))//与当前的不同才切换
                {
                    serialPort1.BaudRate = Convert.ToInt32(comboBoxBaud.SelectedItem.ToString());
                    CopyBaud = serialPort1.BaudRate;
                }
            }
            catch (Exception)//切换出现错误执行这里
            {
                OpenFlage = false;
                buttonOpen.Invoke(buttonConnectDelegate, "打开串口");
                MessageBox.Show("端口错误,请检查串口", "提示");
            }
        }

干脆再便捷点....一启动软件就自动连接第一个串口号

 private void InitConnect()
        {
            string[] ComName = SerialPort.GetPortNames();//把可用的串口号存入comname
            comboBoxCom.Items.AddRange(ComName);//添加到下拉框
            comboBoxCom.SelectedIndex = comboBoxCom.Items.Count > 0 ? 0 : -1;//显示第一个

            if (comboBoxCom.SelectedIndex != -1)
            {
                try
                {
                    serialPort1.PortName = comboBoxCom.Text;
                    serialPort1.BaudRate = Convert.ToInt32(comboBoxBaud.Text);
                    serialPort1.Open();
                    OpenFlage = true;
                    CopyPortName = serialPort1.PortName;//记录COM口号
                    CopyBaud = serialPort1.BaudRate;//记录波特率
                    buttonOpen.Invoke(buttonConnectDelegate, "关闭串口");
                }
                catch (Exception)//其余意外情况执行这里
                {
                    OpenFlage = false;
                    buttonOpen.Invoke(buttonConnectDelegate, "打开串口");
                    MessageBox.Show("端口错误,请检查串口", "提示");
                }
            }
        }

 private void Form1_Load(object sender, EventArgs e)
        {
            buttonConnectDelegate = new ButtonConnectDelegate(buttonConnectMethod);//实例化
            showReMsgSerialDelegate = new ShowReMsgSerialDelegate(ShowReMsgMethod);//实例化

            InitConnect();
        }

再便捷一点,让软件打开一个能用的串口号

private void InitConnect()
        {
            string[] ComName = SerialPort.GetPortNames();//把可用的串口号存入comname
            comboBoxCom.Items.AddRange(ComName);//添加到下拉框
            comboBoxCom.SelectedIndex = comboBoxCom.Items.Count > 0 ? 0 : -1;//显示第一个

            if (comboBoxCom.SelectedIndex != -1)
            {
                for (int i = 0; i < comboBoxCom.Items.Count; i++)
                {
                    try
                    {
                        serialPort1.PortName = comboBoxCom.SelectedIndex.ToString();
                        serialPort1.PortName = comboBoxCom.Text;
                        serialPort1.BaudRate = Convert.ToInt32(comboBoxBaud.Text);
                        serialPort1.Open();
                        OpenFlage = true;
                        CopyPortName = serialPort1.PortName;//记录COM口号
                        CopyBaud = serialPort1.BaudRate;//记录波特率
                        buttonOpen.Invoke(buttonConnectDelegate, "关闭串口");
                        break;
                    }
                    catch (Exception)//其余意外情况执行这里
                    {
                        OpenFlage = false;
                        buttonOpen.Invoke(buttonConnectDelegate, "打开串口");
                        if (comboBoxCom.SelectedIndex < comboBoxCom.Items.Count - 1)
                        {
                            comboBoxCom.SelectedIndex++;
                        }
                        //MessageBox.Show("端口错误,请检查串口", "提示");
                    }
                }
            }
        }

 
 
 
再优化点,,就是软件关闭的时候释放用到的资源

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            try
            {
                serialPort1.Dispose();
            }
            catch (Exception)
            {
            }
        }

好,现在做发送部分

/// <发送数据按钮事件>
        ///
        ///
        ///
        ///
        private void buttonSend_Click(object sender, EventArgs e)
        {
            if (!checkBoxHexSend.Checked)//字符发送
            {
                byte[] sendbyte = Encoding.Default.GetBytes(textBoxSend.Text);
                try { serialPort1.Write(sendbyte, 0, sendbyte.Length); }
                catch (Exception) { MessageBox.Show("请检查串口", "提示!"); }
            }
            else//16形式进制发送
            {
                byte[] sendbyte = strToToHexByte(textBoxSend.Text);
                try { serialPort1.Write(sendbyte, 0, sendbyte.Length); }
                catch (Exception) { MessageBox.Show("请检查串口", "提示!"); }
            }
        }

/// <显示串口发送的信息>
        ///
        ///
        ///
        private void ShowSeMsgMethod(byte[] by)
        {
            string getMsg = string.Empty;
            if (checkBoxHexSend.Checked)//16进制发送
            {
                getMsg = byteToHexStr(by); //用到函数byteToHexStr
            }
            else
            {
                getMsg = new ASCIIEncoding().GetString(by);
            }
            textBoxSend.AppendText(getMsg);
        }

其实和接收数据的文本框一样的处理

private void checkBoxHexSend_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxHexSend.Checked)
            {
                try
                {
                    byte[] by = StringToByte(textBoxSend.Text);
                    textBoxSend.Clear();
                    textBoxSend.BeginInvoke(showSeMsgSerialDelegate, by);
                }
                catch (Exception)
                {
                    //MessageBox.Show(ex.ToString());
                }
            }
            else
            {
                try
                {
                    byte[] by = strToToHexByte(textBoxSend.Text);
                    textBoxSend.Clear();
                    textBoxSend.BeginInvoke(showSeMsgSerialDelegate, by);
                }
                catch (Exception)
                {
                    //MessageBox.Show(ex.ToString());
                }
            }
        }

再加一项功能,,就是说在串口意外断开的时候能够检测出来加入下面这个函数

        /// <检测串口是否断开>
        ///
        ///
        ///
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x0219)
            {
                if (m.WParam.ToInt32() == 0x8004)
                {
                    if (OpenFlage == true)//确定串口一开始是打开的
                    {
                        if (!serialPort1.IsOpen)//是当前串口意外关闭
                        {
                            OpenFlage = false;                                           
                            try
                            {
                                buttonOpen.Invoke(buttonConnectDelegate, "打开串口");
                                /*重新添加一下串口号*/
                                string[] ComName = SerialPort.GetPortNames();//把可用的串口号存入comname
                                comboBoxCom.Items.Clear();//先清除一下,防止重复添加
                                comboBoxCom.Items.AddRange(ComName);//添加到下拉框
                                comboBoxCom.SelectedIndex = comboBoxCom.Items.Count > 0 ? 0 : -1;//显示第一个

                                serialPort1.Dispose();//释放资源
                            }
                            catch (Exception)
                            {

                            }
                        }
                    }
                }
            }
            base.WndProc(ref m);
        }

到这里只是做了一个串口助手
其余的呢就简单了
看现在的界面

对了我规定了协议,,第一个字节代表命令,01代表后面是汉字数据,02代表正弦波数据,03矩形波数据,,04三角波数据
数据的最后两位是CRC16校验
显示汉字部分
 

/// <发送显示的汉字>
        ///
        ///
        ///
        ///
        private void buttonSendChinese_Click(object sender, EventArgs e)
        {
            byte[] sendby = Encoding.Default.GetBytes(textBoxChinese.Text.ToString());
            byte[] sendbyte = new byte[sendby.Length + 1];

            sendbyte[0] = 0x01;
            for (int i = 0; i < sendby.Length; i++)
            {
                sendbyte[i+1] = sendby[i];
            }

            SerialSend(sendbyte);
        }

 
 

/// <串口发送数据函数>
        ///
        ///
        ///
        private void SerialSend(byte[] byt)
        {
            int crc = 0;

            byte[] sendbyte = new byte[byt.Length + 2];

            for (int i = 0; i < byt.Length;i++ )
            {
                sendbyte[i] = byt[i];
            }

            crc = crc16_modbus(byt, byt.Length);//计算CRC
            byte[] Crcbyte = System.BitConverter.GetBytes(crc);//得到CRC

            sendbyte[sendbyte.Length - 2] = Crcbyte[0];
            sendbyte[sendbyte.Length - 1] = Crcbyte[1];

            try
            {
                serialPort1.Write(sendbyte, 0, sendbyte.Length);
            }
            catch (Exception)
            {
                MessageBox.Show("请检查串口", "提示!");
            }
        }

正弦波以及其余波形的方案
 

 byte[] sendbyte = new byte[3];
            if(trackBarSinFlage == 1)//正弦波
            {
                trackBarSinCnt++;
                if (trackBarSinCnt>=5)
                {
                    trackBarSinFlage = 0;
                    trackBarSinCnt = 0;
                    sendbyte[0] = 0x02;
                    sendbyte[1] = Convert.ToByte(trackBarSinF.Value);//正弦波F
                    sendbyte[2] = Convert.ToByte(trackBarSinH.Value);//正弦波H

                    SerialSend(sendbyte);
                }
            }

这段代码放在了定时器2里面,,,我这样做的,只要拖动滑块后500Ms没在改变滑块的值,那么就把当前滑块的值发给单片机,让单片机显示出来
我没有做成一直发给单片机的,,因为12864本身刷新整个界面就慢,,一直发也没什么用.............
 
其余的亲们看源码吧!
 
 
 
现在做做下位机--单片机程序
由于单片机程序太多了,所以就事先做好了底层的了,,,就先看一看
直接贴上来把

#define _12864_C_
#include "include.h"
#include "12864.h"

/**
* @brief  延时us函数
* @param  Time 延时微秒数
* @param  None
* @param  None
* @retval None
* @example
**/
void DelayUs(int Time)   //误差 -0.173611111111us
{
    while(Time --)
    {
        _nop_();
  }
}

void Init12864()
{
    WriteCom(0x30);// 基本指令(DL=1)
    WriteCom(0x30);// 基本指令(RE=0)
    WriteCom(0x0C);// 打开整体显示(不显示光标)
    WriteCom(0x01);// RAM地址归零
    DelayUs(2000);   
    WriteCom(0x06);// 游标自动加一
}

void CRAM_OFF()//关闭显示
{
    WriteCom(0x30);     //DL=1:8-BIT interface
    WriteCom(0x30);     //RE=0:basic instruction
    WriteCom(0x08);      //Display OFF,Cursor OFF,Cursor position blink OFF
    WriteCom(0x01);     //CLEAR
    DelayUs(2000);
}

void CRAM_ON()//打开显示
{
    WriteCom(0x30);// 基本指令(DL=1)
    WriteCom(0x30);// 基本指令(RE=0)
    WriteCom(0x0C);// 打开整体显示(不显示光标)
}

/**
* @brief  向12864内写入数据
* @param  Data 数据
* @param  None
* @param  None
* @retval None
* @example
**/
void WriteData(char Data)
{
    RS = 1;//数据
    RW = 0;//写入
    E  = 0;//使能拉低
    DelayUs(1);
    Port = Data;
    DelayUs(1);
    E = 1;
    DelayUs(1);
    E = 0;
    DelayUs(80);
}

/**
* @brief  向12864内写入命令
* @param  Com  命令
* @param  None
* @param  None
* @retval None
* @example
**/
void WriteCom(char Com)
{
    E  = 0;//使能拉低
    RS = 0;//命令
    RW = 0;//写入
    DelayUs(1);
    Port = Com;
    DelayUs(1);
    E = 1;
    DelayUs(1);
    E = 0;
    DelayUs(80);
}

/**
* @brief  从12864内读出数据
* @param  None
* @param  None
* @param  None
* @retval None
* @example 读出的数据
**/
char ReadData()
{
    char Data;
    Port = 0xff;
    RS = 1; //数据
    RW = 1; //读取
    E  = 1;
    Data=Port;//读取数据
    E  = 0;
    DelayUs(80);
    return(Data);  
}

/**
* @brief  显示图片
* @param  char  *img
* @param  None
* @param  None
* @retval None
* @example
**/
void DisplayImage(char  *img)//横向取膜
{
    char i,j;
 
    WriteCom(0x36); //图形方式
 
    for(i=0;i<32;i++)
    {
        WriteCom(0x80+i);
        WriteCom(0x80);     
   
        for(j=0;j<16;j++)
        {
            WriteData(*img++);
        }
    }
   
     for(i=0;i<32;i++)
  {
        WriteCom(0x80+i);
        WriteCom(0x88);
        for(j=0;j<16;j++)
        {
            WriteData(*img++);
        }
    }
}

/**
* @brief  在指定位置画一个点
* @param  char x,char y, char Flage
* @param  None
* @param  None
* @retval None
* @example
**/
void DrawPoint(char x,char y, char Flage)
{
   
    char x_dyte,x_byte; //定义列地址的字节位,及在字节中的哪1位
    char y_dyte,y_byte; //定义为上下两个屏(取值为0,1),行地址(取值为0~31)
    char GDRAM_hbit,GDRAM_lbit;
   
    WriteCom(0x36); //绘图模式命令
 
  /***X,Y坐标互换,即普通的X,Y坐标***/

    x_dyte=y/16; //计算在16个字节中的哪一个
    x_byte=y&0x0f; //计算在该字节中的哪一位
    y_dyte=x/32; //0为上半屏,1为下半屏
    y_byte=x&0x1f; //计算在0~31当中的哪一行
    WriteCom(0x80+y_byte); //设定行地址(y坐标)
    WriteCom(0x80+x_dyte+8*y_dyte); //设定列地址(x坐标),并通过8*y_Dyte选定上下屏
  DelayUs(1);
   
    ReadData();
    GDRAM_hbit=ReadData();//读取当前显示高8位数据
    GDRAM_lbit=ReadData();//读取当前显示低8位数据
 
    if(Flage == 1)
    {
        WriteCom(0x80+y_byte); //设定行地址(y坐标)
      WriteCom(0x80+x_dyte+8*y_dyte); //设定列地址(x坐标),并通过8*y_Dyte选定上下屏
        DelayUs(1);
       
        if(x_byte<8) //判断其在高8位,还是在低8位
        {
            WriteData(GDRAM_hbit|(0X01<<(7-x_byte)));   //显示GDRAM区高8位数据
            WriteData(GDRAM_lbit); //显示GDRAM区低8位数据
        }
        else
        {
            WriteData(GDRAM_hbit);
            WriteData(GDRAM_lbit|(0x01<<(15-x_byte)));
        }
  }       
    else
    {
        WriteData((0x00)); //清除GDRAM区高8位数据
        WriteData((0x00)); //清除GDRAM区低8位数据
    }
}

/**
* @brief  八点画圆
* @param  char x,char y,char xc,char yc
* @param  None
* @param  None
* @retval None
* @example
**/
void plotC(char x,char y,char xc,char yc)
{
    DrawPoint(xc+x,yc+y,1);
    DrawPoint(xc+x,yc-y,1);
    DrawPoint(xc-x,yc+y,1);
    DrawPoint(xc-x,yc-y,1);
    DrawPoint(xc+y,yc+x,1);
    DrawPoint(xc+y,yc-x,1);
    DrawPoint(xc-y,yc+x,1);
    DrawPoint(xc-y,yc-x,1);
}

/**
* @brief  在指定位置画一个半径为R的圆
* @param  char x0,char y0, char r
* @param  None
* @param  None
* @retval None
* @example
**/
void DrawCircle(char xc,char yc, char r)
{
    char x,y,d;
    y=r;
    d=3-(r<<1);
    x=0;
    while(x<=y)
    {
        plotC(x,y,xc,yc);
        if(d < 0)
        {
      d+=(x<<2)+6;
    }
        else
        {
            d+=((x-y)<<2)+10;
            y=y-1;
        }
        x=x+1;
    }
}

/**
* @brief  显示汉字
* @param  x:行号, y:列号, k:个数, *p:数据
* @param  None
* @param  None
* @retval None
* @example
**/
void Chinese(char x,char y,char k,char *p)
{
    char hang=0,out=0,i=0;
    y=y-1;
    switch(x)
    {
        case 1:hang=0x80;break;
        case 2:hang=0x90;break;
        case 3:hang=0x88;break;
        case 4:hang=0x98;break;       
    }
    out=hang+y;
    WriteCom(out);
    for(i=0;i<k*2;i++)
    {
        switch(i)
      {
            case 16:WriteCom(0x90);break;
            case 32:WriteCom(0x88);break;
            case 48:WriteCom(0x98);break;    
      }
        WriteData(*p);
        p++;
    }
}

/**
* @brief  清除液晶GDRAM中的随机数据
* @param  None
* @param  None
* @param  None
* @retval None
* @example
**/
void ClearGDRAM(void)
{
  char i,j,k;

    WriteCom(0x34);  //打开扩展指令集
    i=0x80;
    for(j=0;j<32;j++)
    { 
        WriteCom(i++);
        WriteCom(0x80);
        for(k=0;k<16;k++)
        {
          WriteData(0x00);
      }
    }

    i=0x80;
    for(j=0;j<32;j++)
    {
        WriteCom(i++);
        WriteCom(0x88);
        for(k=0;k<16;k++)
        {
          WriteData(0x00);
      }
    }
    WriteCom(0x30); //回到基本指令集   
}

/**
* @brief 
* @param  None
* @param  None
* @param  None
* @retval None
* @example
**/
void ClearDDRAM()
{
    WriteCom(0x30);     //DL=1:8-BIT interface
    WriteCom(0x30);     //RE=0:basic instruction
    WriteCom(0x0C);      //Display ON,Cursor OFF,Cursor position blink OFF
    WriteCom(0x01);     //CLEAR
    DelayUs(5000);
}

/**
* @brief  正弦波
* @param  None
* @param  None
* @param  None
* @retval None
* @example
**/
void fsin(char f,char h)
{
  char i,j;
  for(i=0;i<127;i++)
    {
        j=32-h*sin(i*3.14/f);
        DrawPoint(j,i,1);
    }
}

/**
* @brief  矩形波
* @param  None
* @param  None
* @param  None
* @retval None
* @example
**/
void RecWave(char f,char h)
{
  char i,j,flag=0;
   
  for(i=0;i<127;i++)
  {
        if(f <= 0) break;
        if(h >= 32) break;
       
    if(i%f==0)
    {
      for(j=32-h;j<=32+h;j++)
        DrawPoint(j,i,1);
      if(flag==0)
        flag=1;
      else
        flag=0;
    }
    else
    {
      if(flag==0)
        j=32-h;
      else
        j=32+h;
      DrawPoint(j,i,1);
    }
  }
}

/**
* @brief  画一条线
* @param  int x0, int y0,起点
* @param  int x1, int y1,终点
* @param  None
* @retval None
* @example
**/
void DrawLine(char x0, char y0, char x1, char y1)
{
    char x,y;
    char dx;// = abs(x1 - x0);
    char dy;// = abs(y1 - y0);

    if(y0==y1)
    {
        if(x0<=x1)
        {
            x=x0;
        }
        else
        {
            x=x1;
            x1=x0;
        }
            while(x <= x1)
            {
                DrawPoint(x,y0,1);
                x++;
            }
            return;
    }
    else if(y0>y1)
    {
        dy=y0-y1;
    }
    else
    {
        dy=y1-y0;
    }
 
    if(x0==x1)
    {
        if(y0<=y1)
        {
            y=y0;
        }
        else
        {
            y=y1;
            y1=y0;
        }
        while(y <= y1)
        {
            DrawPoint(x0,y,1);
            y++;
        }
        return;
    }
    else if(x0 > x1)
    {
        dx=x0-x1;
        x = x1;
        x1 = x0;
        y = y1;
        y1 = y0;
    }
    else
    {
        dx=x1-x0;
            x = x0;
            y = y0;
    }

    if(dx == dy)
    {
        while(x < x1)
        {
            x++;
            if(y>y1)
            {
                y--;
            }
            else
            {
                    y++;
            }
            DrawPoint(x,y,1);
        }
    }
    else
    {
        DrawPoint(x, y,1);
            if(y < y1)
            {
                if(dx > dy)
                {
                    char p = dy * 2 - dx;
                    char twoDy = 2 * dy;
                    char twoDyMinusDx = 2 * (dy - dx);
                    while(x < x1)
                    {
                        x++;
                        if(p < 0)
                        {
                                p += twoDy;
                        }
                        else
                        {
                                y++;
                                p += twoDyMinusDx;
                        }
                        DrawPoint(x, y,1);
                    }
                }
                else
                {
                    char p = dx * 2 - dy;
                    char twoDx = 2 * dx;
                    char twoDxMinusDy = 2 * (dx - dy);
                    while(y < y1)
                    {
                        y++;
                        if(p < 0)
                        {
                                p += twoDx;
                        }
                        else
                        {
                                x++;
                                p+= twoDxMinusDy;
                        }
                        DrawPoint(x, y,1);
                    }
                }
            }
            else
            {
                if(dx > dy)
                {
                    char p = dy * 2 - dx;
                    char twoDy = 2 * dy;
                    char twoDyMinusDx = 2 * (dy - dx);
                    while(x < x1)
                    {
                        x++;
                        if(p < 0)
                        {
                                p += twoDy;
                        }
                        else
                        {
                                y--;
                                p += twoDyMinusDx;
                        }
                        DrawPoint(x, y,1);
                    }
                }
                else
                {
                    char p = dx * 2 - dy;
                    char twoDx = 2 * dx;
                    char twoDxMinusDy = 2 * (dx - dy);
                    while(y1 < y)
                    {
                        y--;
                        if(p < 0)
                        {
                                p += twoDx;
                        }
                        else
                        {
                                x++;
                                p+= twoDxMinusDy;
                        }
                        DrawPoint(x, y,1);
                    }
                }
            }
    }
}

/**
* @brief  显示三角波
* @param  char f,char h,频率,幅值
* @param  None
* @param  None
* @retval None
* @example
**/
void TriWave(char f,char h)//显示三角波
{
    char i,j=0,flag=0;
    char x1,x2;
    for(i=0;i<127;i++)
    {
        if(i%f==0)
        {
            if(flag==0)
            {
                x1 = i;
        flag=1;
                j++;
      }
            else
            {
        x2 = i;
                flag=0;
      }
            if(flag == 1)
            {
                if(j>=2)
                {
                    DrawLine(32+h,x2,32-h,x1);
                }
            }
            else
            {
                DrawLine(32-h,x1,32+h,x2);
            }
        }
    }
}

View Code

 
 

#ifndef __12864_H_
#define __12864_H_
#include

#ifndef _12864_C_
#define _12864_C_ extern
#else
#define _12864_C_
#endif

sbit RS = P3^7;//数据\命令选择
sbit RW = P3^6;//读\写
sbit E  = P3^5;//使能

sfr Port = 0xA0;

void DelayUs(int Time);
void Init12864();
void WriteData(char Data);
void WriteCom(char Com);
char ReadData();
void DisplayImage(char  *img);
void CRAM_OFF();
void CRAM_ON();
void DrawPoint(char x,char y, char Flage);
void DrawCircle(char x0,char y0, char r);
void Chinese(char x,char y,char k,char *p);
void ClearGDRAM(void);
   

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言C#.NET频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程