欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 738|回復: 4
打印 上一主題 下一主題
收起左側

STC8G/H通用 SPI驅動WS2812 SPI模擬單總線

[復制鏈接]
跳轉到指定樓層
樓主
WS2812的單總線是根據高電平時間決定是邏輯1還是邏輯0的,而SPI恰巧是不歸零碼,只有當數據比特改變時,才會改變MOSI的電平。
比如輸出11110111的時候,前四個1MOSI都是高電平,不會回到低電平,因此可以使用SPI模擬2812單總線,時序很容易控制,不需要軟件TOGGLE。
STC8G的spi算是比較簡陋的類型,功能不是很多,但是只是驅動ws2812彩燈的話,是完全足夠的,簡陋反而是優點,不需要寫太多的寄存器,這個功能我一下午就寫出來了。
tips:STC的spi,MOSI在空閑時會輸出MISO采集到的電平,但是一些情況下,比如使用8腳單片機,MOSI引腳又不能閑置,可以關閉MISO引腳的數字輸入功能,這樣子,軟件在讀取MISO引腳電平的時候不論外部電平,始終返回0。這樣MISO引腳就可以用作他用了。
同理SCLK,SPI時鐘引腳,只要設置為高阻模式,就可以不受SPI控制,并且可以自由讀取外部電平,用作按鍵輸入使用。
下面是一套驅動庫與測試范例代碼,這是一個底層接口,你可以自己封裝為頭文件,也可以基于
WS2812_Send_Data(unsigned char WS2812_Num,unsigned char Red,unsigned char Green,unsigned char Blue)
的底層接口,實現流水燈,RGB等等效,范例中給出的是實現RGB顏色平滑變化的代碼。
注意:主頻一定要設置為24MHZ,否則可能導致高低電平時間不準,無法點亮ws2812
理論上,STC8單片機工作在從機模式下,是可以從MISO輸出一樣的信息的,但是我這里試了兩三次沒有成功,就沒有繼續做,沒必要了,已經足夠。
STC8H系列的SPI雖然比STC8G系列多了一些功能,但是基本的SPI寄存器是一樣的,理論上STC8H系列也可以使用,我就懶得測試了,網友們可以測試一次。本庫函數目前只在STC8G1K08A上使用過。
下面的代碼已經實現了基本的Init,Pinset等arduino風格接口,你可以很輕松的封裝為頭文件,當然也可以不封裝,直接作為C文件調用。
#include "STC8G.H"
#include "intrins.h"
//下面的代碼,要求使用SPI實現驅動WS2812彩燈
//6MHZ時鐘下,SPI傳輸一位需要166.7ns
//使用本驅動庫,必須設置系統時鐘為24Mhz,否則你需要手動修改一碼零碼高低電平時間
#define High_Code 0xf8//11111000
#define Zero_Code 0xC0//11000000
//開始發送時,SPIF = 0,結束發送后SPIF = 1;
void SPI_Send_1_Byte(unsigned char SPI_Data){
    SPDAT = SPI_Data;//寫入后,硬件置SPIF = 0;
    while(!(SPSTAT & 0x80));//SPI控制器發送完數據后,退出while循環
    SPSTAT = 0xC0;//清空中斷標志
}
void WS2812_Lightup(){
    //調用SPI_Send_1_Byte,發送80us的0x00,使燈珠亮起
    //80us/0.1667*8 = 60,循環發送40個0
    unsigned char i;
    for(i = 0;i < 40;i++){//循環40次
        SPI_Send_1_Byte(0x00);}
}
void WS2812_PinSet(unsigned char Pin){
    //傳入引腳,配置引腳為推挽
    if(Pin == 34){//STC8 MOSI
        P_SW1 |= 0X0C;//B3B2 = 1;
        SPCTL |= 0X10;//B4 MSTR = 1;
        P3IE &= 0XF7; //P33IE = 0;
        P3M0 |= 0x10; P3M1 &= ~0x10;}//P34推挽
    else if(Pin == 40){//MOSI
        P_SW1 |= 0X08;//B3 = 1;
        SPCTL |= 0X10;//MSTR = 1;
        P4IE &= 0XFD;//P41IE = 0;
        P4M0 |= 0x01; P4M1 &= ~0x01;}//P40推挽
    else if(Pin == 23){//MOSI
        P_SW1 |= 0X04;//B2 = 1;
        SPCTL |= 0X10;//MSTR = 1;
        P2IE &= 0XEF;//P24IE = 0;
        P2M0 |= 0x08; P2M1 &= ~0x08;}//P23推挽
    else if(Pin == 13){//MOSI
        P_SW1 &= 0XF3;//B3B2 = 0;
        SPCTL |= 0X10;//MSTR = 1;
        P1IE &= 0XEF;//B4 P14IE = 0
        P1M0 |= 0x08; P1M1 &= ~0x08;}//P13推挽
    else if(Pin == 54){//STC8G1K08A 8PIN MOSI
        P_SW1 &= 0XF3;//B3B2=0
        SPCTL |= 0X10;//B4 MSTR = 1,主機
        P3IE &= 0xF7;//關閉P33 MISO數字輸入
        P5M0 |= 0x10; P5M1 &= ~0x10;}//P54推挽
}
void WS2812_Init(unsigned char Pin_Sel){//對于STC8G1K08A 8Pin需要執行不同的引腳初始化
    //初始化,并決定是否為主機從機
    P_SW1 &= 0XF3;//B3B2 = 0;
    P_SW2 |= 0X80;//允許訪問擴展寄存器
    SPSTAT = 0XC0;//清零中斷標志
    SPCTL = 0XD4;//SPEN = 1;SSIG = 1;先發高位;主機模式;時鐘空閑低電平;后時鐘沿采樣;SPI CLK為sysclk/4;
    WS2812_PinSet(Pin_Sel);
}
void WS2812_Deinit(){//關閉SPI,但引腳解綁需要根據需求手動配置
    SPSTAT = 0XC0;
    SPCTL &= 0XBF;//SPEN = 0;
}
void WS2812_Send_Data(unsigned char WS2812_Num,unsigned char Red,unsigned char Green,unsigned char Blue){
    //發送數據順序為GRB
    unsigned char i,j;
    unsigned char dat;
    for(j = 0;j < WS2812_Num;j++){
    //Green
    dat = Green;
    for(i = 0; i < 8; i++){
        if(dat & 0x80) SPI_Send_1_Byte(High_Code); // 提取最高位,判斷發1碼還是0碼
        else           SPI_Send_1_Byte(Zero_Code);
        dat <<= 1; // 左移一位,準備發送下一位
    }
   
    //Red
    dat = Red;
    for(i = 0; i < 8; i++){
        if(dat & 0x80) SPI_Send_1_Byte(High_Code);
        else           SPI_Send_1_Byte(Zero_Code);
        dat <<= 1;
    }
    //Blue
    dat = Blue;
    for(i = 0; i < 8; i++){
        if(dat & 0x80) SPI_Send_1_Byte(High_Code);
        else           SPI_Send_1_Byte(Zero_Code);
        dat <<= 1;
    }
    }
    WS2812_Lightup();
}
void WS2812_Color_Encoder(unsigned char Red,unsigned char Green,unsigned char Blue){
   
}
void WS2812_Test(){
    static unsigned char phase = 0;
    unsigned int i = 65535;
    static unsigned char r,g,b;
    while(i--);
    if (phase < 85) {
        // 紅 -> 綠
        r = 255 - (phase * 3);     // 255 → 0
        g = phase * 3;             // 0 → 255
        b = 0;
    } else if (phase < 170) {
        // 綠 -> 藍
        unsigned char t = phase - 85;
        r = 0;
        g = 255 - (t * 3);         // 255 → 0
        b = t * 3;                 // 0 → 255
    } else {
        // 藍 -> 紅
        unsigned char t = phase - 170;
        r = t * 3;                 // 0 → 255
        g = 0;
        b = 255 - (t * 3);         // 255 → 0
    }
    phase++;
    WS2812_Send_Data(10,r,g,b);
}
void main(){
    WS2812_Init(54);
    while(1){
        //WS2812_Send_Data(10,44,10,96);//RGB
        WS2812_Test();
    }
}

IMG_20260223_195306.jpg (2.86 MB, 下載次數: 0)

IMG_20260223_195306.jpg

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏6 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:1155837 發表于 2026-3-12 16:24 | 只看該作者
已經在STC8H1K08T上測試通過,代碼在STC8H上同樣可用
回復

使用道具 舉報

板凳
ID:433219 發表于 2026-3-15 15:21 | 只看該作者
有點意思。。測試一下
回復

使用道具 舉報

地板
ID:71233 發表于 2026-3-16 11:49 | 只看該作者
SPI通訊需要多個IO口,現在雖然只用到一個IO去控制WS2812,是不是SPI其他端口也無法另作他用了?
回復

使用道具 舉報

5#
ID:1155837 發表于 2026-3-18 12:15 | 只看該作者
lmn2005 發表于 2026-3-16 11:49
SPI通訊需要多個IO口,現在雖然只用到一個IO去控制WS2812,是不是SPI其他端口也無法另作他用了?

忘記說了,可以用的,MISO需要關閉數字輸入功能,可做電平控制或PWM輸出,CLK引腳僅能設為高阻模式,不需要關閉數字輸入,可做電平采集或ADC。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表